예제 #1
0
        /// <inheritdoc/>
        public async Task <IDictionary <string, string> > GetExtensionLabelsAsync(ApplicationWrapper application, ServiceWrapper service, CancellationToken cancellationToken)
        {
            _ = application ?? throw new ArgumentNullException(nameof(application));
            _ = service ?? throw new ArgumentNullException(nameof(service));
            _ = application.ApplicationTypeName ?? throw new ArgumentNullException($"{nameof(application)}.{nameof(application.ApplicationTypeName)}");
            _ = application.ApplicationTypeVersion ?? throw new ArgumentNullException($"{nameof(application)}.{nameof(application.ApplicationTypeVersion)}");
            _ = service.ServiceTypeName ?? throw new ArgumentNullException($"{nameof(service)}.{nameof(service.ServiceTypeName)}");
            _ = service.ServiceName ?? throw new ArgumentNullException($"{nameof(service)}.{nameof(service.ServiceName)}");

            string serviceManifestName;

            try
            {
                serviceManifestName = await _serviceFabricCaller.GetServiceManifestName(application.ApplicationTypeName, application.ApplicationTypeVersion, service.ServiceTypeName, cancellationToken);
            }
            catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested)
            {
                throw;
            }
            catch (Exception ex) // TODO: davidni: not fatal?
            {
                throw new ServiceFabricIntegrationException($"Failed to get service manifest name for service type {service.ServiceTypeName} of application type {application.ApplicationTypeName} {application.ApplicationTypeVersion} from Service Fabric: {ex}.");
            }

            if (serviceManifestName == null)
            {
                throw new ServiceFabricIntegrationException($"No service manifest name was found for service type {service.ServiceTypeName} of application type {application.ApplicationTypeName} {application.ApplicationTypeVersion}.");
            }

            string rawServiceManifest;

            try
            {
                rawServiceManifest = await _serviceFabricCaller.GetServiceManifestAsync(application.ApplicationTypeName, application.ApplicationTypeVersion, serviceManifestName, cancellationToken);
            }
            catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested)
            {
                throw;
            }
            catch (Exception ex) // TODO: davidni: not fatal?
            {
                throw new ServiceFabricIntegrationException($"Failed to get service manifest {serviceManifestName} of service type {service.ServiceTypeName} of application type {application.ApplicationTypeName} {application.ApplicationTypeVersion} from Service Fabric: {ex}.");
            }

            if (rawServiceManifest == null)
            {
                throw new ServiceFabricIntegrationException($"No service manifest named '{serviceManifestName}' was found for service type {service.ServiceTypeName} of application type {application.ApplicationTypeName} {application.ApplicationTypeVersion}.");
            }

            // TODO: gathering labels from multiple servicetypes within the same service would result in multiple
            // calls to the SF client and multiple XML parses. We should consider creating an instance of this class
            // per application type to reuse that data. Since this is uncommon, for now we follow the na�ve implementation.
            var result = await ExtractLabelsAsync(rawServiceManifest, service.ServiceTypeName, cancellationToken);

            ApplyAppParamReplacements(result, application, service);

            if (result.GetValueOrDefault("Service.EnableDynamicOverrides", null)?.ToLower() == "true")
            {
                // Override with properties
                IDictionary <string, string> properties;
                try
                {
                    properties = await _serviceFabricCaller.EnumeratePropertiesAsync(service.ServiceName, cancellationToken);
                }
                catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    throw new ServiceFabricIntegrationException($"Failed to get properties for {service.ServiceName}.", ex);
                }

                OverrideLabels(ref result, properties);
            }

            return(result);
        }
예제 #2
0
        private async Task LoadServiceDataAsync(Dictionary <string, string> data, ApplicationWrapper application, string appPrefix,
                                                ServiceWrapper service, CancellationToken cancellationToken)
        {
            string serviceManifestName;

            try
            {
                serviceManifestName = await _serviceFabricCaller.GetServiceManifestName(application.ApplicationTypeName,
                                                                                        application.ApplicationTypeVersion, service.ServiceTypeName, cancellationToken);
            }
            catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested)
            {
                throw;
            }
            catch (Exception ex) // TODO: davidni: not fatal?
            {
                throw new ServiceFabricIntegrationException(
                          $"Failed to get service manifest name for service type {service.ServiceTypeName} of application type {application.ApplicationTypeName} {application.ApplicationTypeVersion} from Service Fabric: {ex}.");
            }

            if (serviceManifestName == null)
            {
                throw new ServiceFabricIntegrationException(
                          $"No service manifest name was found for service type {service.ServiceTypeName} of application type {application.ApplicationTypeName} {application.ApplicationTypeVersion}.");
            }

            string rawServiceManifest;

            try
            {
                rawServiceManifest = await _serviceFabricCaller.GetServiceManifestAsync(application.ApplicationTypeName,
                                                                                        application.ApplicationTypeVersion, serviceManifestName, cancellationToken);
            }
            catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested)
            {
                throw;
            }
            catch (Exception ex) // TODO: davidni: not fatal?
            {
                throw new ServiceFabricIntegrationException(
                          $"Failed to get service manifest {serviceManifestName} of service type {service.ServiceTypeName} of application type {application.ApplicationTypeName} {application.ApplicationTypeVersion} from Service Fabric: {ex}.");
            }

            if (rawServiceManifest == null)
            {
                throw new ServiceFabricIntegrationException(
                          $"No service manifest named '{serviceManifestName}' was found for service type {service.ServiceTypeName} of application type {application.ApplicationTypeName} {application.ApplicationTypeVersion}.");
            }

            using (var reader = XmlReader.Create(new StringReader(rawServiceManifest), XmlReaderHelper.CreateSafeXmlSetting()))
            {
                XDocument parsedManifest;
                try
                {
                    parsedManifest = await XDocument.LoadAsync(reader, LoadOptions.None, cancellationToken);
                }
                catch (System.Xml.XmlException ex)
                {
                    // TODO: we don't know if the service wants to use the gateway yet, so not sure if this classifies as config error (considering it will escalate into a bad health report)
                    throw new ConfigException("Failed to parse service manifest XML.", ex);
                }

                var elements = parsedManifest
                               .Elements(XmlReaderHelper.XNSServiceManifest + "ServiceManifest")
                               .Elements(XmlReaderHelper.XNSServiceManifest + "ServiceTypes")
                               .Elements().Where(s => (string)s.Attribute("ServiceTypeName") == service.ServiceTypeName)
                               .Elements(XmlReaderHelper.XNSServiceManifest + "Extensions")
                               .Elements(XmlReaderHelper.XNSServiceManifest + "Extension").Where(s =>
                                                                                                 (string)s.Attribute("Name") == ConfigurationValues.ExtensionName)
                               .Elements(XmlReaderHelper.XNSFabricNoSchema + "Service");

                if (!elements.Any())
                {
                    return;
                }

                var serviceId     = service.ServiceName.ToString().Replace($"{application.ApplicationName}/", string.Empty);
                var servicePrefix =
                    $"{appPrefix}Services{ConfigurationPath.KeyDelimiter}{serviceId}{ConfigurationPath.KeyDelimiter}";
                data[$"{servicePrefix}Id"]              = serviceId;
                data[$"{servicePrefix}Name"]            = service.ServiceName.ToString();
                data[$"{servicePrefix}TypeName"]        = service.ServiceTypeName;
                data[$"{servicePrefix}Kind"]            = service.ServiceKind.ToString();
                data[$"{servicePrefix}ManifestVersion"] = service.ServiceManifestVersion;

                await using (var stream = new MemoryStream())
                {
                    await using (var sw = new StreamWriter(stream))
                    {
                        using (var writer = new XmlNoNamespaceWriter(sw, new XmlWriterSettings {
                            CloseOutput = false
                        }))
                        {
                            foreach (var element in elements)
                            {
                                element.Save(writer);
                            }

                            writer.Flush();
                            await sw.FlushAsync();

                            var sections = XmlStreamToDictionaryParser.Parse(stream, (options) =>
                            {
                                options.KeyDelimiter = ConfigurationPath.KeyDelimiter;
                                options.Parents      = new List <string>(servicePrefix.Split(ConfigurationPath.KeyDelimiter,
                                                                                             StringSplitOptions.RemoveEmptyEntries));
                                options.IsIndexAttribute = (attribute, stack) =>
                                {
                                    switch (stack.FirstOrDefault())
                                    {
                                    case "Endpoint":
                                        return(string.Equals(attribute, "Id", StringComparison.OrdinalIgnoreCase));

                                    case "Route":
                                        return(string.Equals(attribute, "Id", StringComparison.OrdinalIgnoreCase));
                                    }

                                    return(false);
                                };
                            });
                            foreach (var section in sections)
                            {
                                data[section.Key] = section.Value;
                            }
                        }
                    }
                }
            }
        }