in gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java [395:635]
private static Map<String, File> generateTopology(final SimpleDescriptor desc,
final File srcDirectory,
final File destDirectory,
final ServiceDiscovery.Cluster cluster,
final List<String> declaredServiceNames,
final Set<String> validServiceNames,
final Map<String, String> serviceVersions,
final Map<String, List<String>> serviceURLs,
final Map<String, Map<String, String>> serviceParams,
final GatewayServices gwServices) {
Map<String, File> result = new HashMap<>();
File topologyDescriptor = null;
try (StringWriter sw = new StringWriter()) {
// Handle the referenced provider configuration
File providerConfigFile = null;
ProviderConfiguration providerConfiguration = null;
String providerConfigReference = desc.getProviderConfig();
if (providerConfigReference != null) {
// Resolve and parse the referenced provider configuration
providerConfigFile = resolveProviderConfigurationReference(providerConfigReference, srcDirectory);
providerConfiguration = handleProviderConfiguration(desc, providerConfigFile);
}
if (providerConfiguration == null) {
throw new IllegalArgumentException("Invalid provider configuration: " + providerConfigReference);
}
result.put(RESULT_REFERENCE, providerConfigFile);
ProviderConfiguration.Provider haProvider = null;
for (ProviderConfiguration.Provider provider : providerConfiguration.getProviders()) {
if ("ha".equals(provider.getRole())) {
haProvider = provider;
break;
}
}
// Collect HA-related service parameters
Map<String, ServiceDiscovery.Cluster.ZooKeeperConfig> haServiceParams = new HashMap<>();
if (cluster != null) {
if (haProvider != null) {
// Collect tne roles declared by the HaProvider
Map<String, String> haProviderParams = haProvider.getParams();
if (haProviderParams != null) {
Set<String> haProviderRoles = haProviderParams.keySet();
for (String haProviderRole : haProviderRoles) {
// For each role declared by the HaProvider, which supports ZooKeeper, try to get
// the ZK ensemble and namespace from the cluster.
ServiceDiscovery.Cluster.ZooKeeperConfig zkConfig =
cluster.getZooKeeperConfiguration(haProviderRole);
if (zkConfig != null) {
haServiceParams.put(haProviderRole, zkConfig);
}
}
}
}
}
// Generate the topology content
sw.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
sw.write("<!--==============================================-->\n");
sw.write("<!-- DO NOT EDIT. This is an auto-generated file. -->\n");
sw.write("<!--==============================================-->\n");
sw.write("<topology>\n");
// KNOX-1105 Indicate that this topology was auto-generated
sw.write(" <generated>true</generated>\n");
// Incorporate the externalized provider configuration content into the topology descriptor
sw.write(" <gateway>\n");
for (ProviderConfiguration.Provider provider : providerConfiguration.getProviders()) {
sw.write(" <provider>\n");
sw.write(" <role>" + provider.getRole() + "</role>\n");
sw.write(" <name>" + provider.getName() + "</name>\n");
sw.write(" <enabled>" + provider.isEnabled() + "</enabled>\n");
for (Map.Entry<String, String> param : provider.getParams().entrySet()) {
sw.write(" <param>\n");
sw.write(" <name>" + param.getKey() + "</name>\n");
sw.write(" <value>" + getXmlEscapedValue(param.getValue()) + "</value>\n");
sw.write(" </param>\n");
}
sw.write(" </provider>\n");
}
sw.write(" </gateway>\n");
// Services
// Sort the service names to write the services alphabetically
Set<String> serviceNames = new TreeSet<>(validServiceNames);
// Add any declared services, which were not validated, but which have ZK-based HA provider config
for (String haServiceName : haServiceParams.keySet()) {
// If the service configured for HA was declared in the descriptor, then add it to the services to be
// serialized (if it's not already included)
if (declaredServiceNames.contains(haServiceName)) {
if (!serviceNames.contains(haServiceName)) {
serviceNames.add(haServiceName);
}
}
}
// Write the service declarations
for (String serviceName : serviceNames) {
sw.write("\n");
sw.write(" <service>\n");
sw.write(" <role>" + serviceName + "</role>\n");
if (serviceVersions.containsKey(serviceName)) {
sw.write(" <version>" + serviceVersions.get(serviceName) + "</version>\n");
}
// Add the service params to the map for serialization
Map<String,String> params = serviceParams.computeIfAbsent(serviceName, k -> new HashMap<>());
ServiceDiscovery.Cluster.ZooKeeperConfig zkConf = haServiceParams.get(serviceName);
// Determine whether to persist the haEnabled param, and to what value
boolean isServiceHaEnabledAuto = false;
boolean isServiceHaEnabled = false;
if (haProvider != null) {
Map<String, String> haParams = haProvider.getParams();
if (haParams != null && haParams.containsKey(serviceName)) {
String serviceHaParams = haParams.get(serviceName);
Map<String,String> parsedServiceHaParams = parseHaProviderParam(serviceHaParams);
String enabledValue = parsedServiceHaParams.get("enabled");
if (enabledValue != null) {
if ("auto".equalsIgnoreCase(enabledValue)) {
isServiceHaEnabledAuto = true;
isServiceHaEnabled = (zkConf != null && zkConf.isEnabled());
} else {
isServiceHaEnabled = "true".equalsIgnoreCase(enabledValue);
}
}
}
}
// If the HA provider configuration for this service indicates an enabled value of "auto", then
// persist the derived enabled value.
if (isServiceHaEnabledAuto) {
params.put(org.apache.knox.gateway.topology.Service.HA_ENABLED_PARAM,
String.valueOf(isServiceHaEnabled));
}
// If the service is configured for ZooKeeper-based HA
if (zkConf != null && zkConf.getEnsemble() != null && isServiceHaEnabled) {
String ensemble = zkConf.getEnsemble();
if (ensemble != null && !ensemble.isEmpty()) {
params.put("zookeeperEnsemble", ensemble);
}
String namespace = zkConf.getNamespace();
if (namespace != null && !namespace.isEmpty() ) {
params.put("zookeeperNamespace", namespace);
}
} else {
// Serialize the service URLs
List<String> urls = serviceURLs.get(serviceName);
if (urls != null) {
for (String url : urls) {
sw.write(" <url>" + url + "</url>\n");
}
}
}
// Params
Map<String, String> svcParams = serviceParams.get(serviceName);
if (svcParams != null) {
for (Entry<String, String> svcParam : svcParams.entrySet()) {
if (!(svcParam.getKey().toLowerCase(Locale.ROOT)).startsWith(SimpleDescriptor.DISCOVERY_PARAM_PREFIX)) {
sw.write(" <param>\n");
sw.write(" <name>" + svcParam.getKey() + "</name>\n");
sw.write(" <value>" + getXmlEscapedValue(svcParam.getValue()) + "</value>\n");
sw.write(" </param>\n");
}
}
}
sw.write(" </service>\n");
}
// Applications
List<SimpleDescriptor.Application> apps = desc.getApplications();
if (apps != null) {
for (SimpleDescriptor.Application app : apps) {
sw.write(" <application>\n");
sw.write(" <name>" + app.getName() + "</name>\n");
// URLs
List<String> urls = app.getURLs();
if (urls != null) {
for (String url : urls) {
sw.write(" <url>" + url + "</url>\n");
}
}
// Params
Map<String, String> appParams = app.getParams();
if (appParams != null) {
for (Entry<String, String> entry : appParams.entrySet()) {
sw.write(" <param>\n");
sw.write(" <name>" + entry.getKey() + "</name>\n");
sw.write(" <value>" + getXmlEscapedValue(entry.getValue()) + "</value>\n");
sw.write(" </param>\n");
}
}
sw.write(" </application>\n");
}
}
sw.write("</topology>\n");
// Write the generated content to a file
String topologyFilename = desc.getName();
if (topologyFilename == null) {
topologyFilename = desc.getCluster();
}
topologyDescriptor = new File(destDirectory, topologyFilename + ".xml");
if (shouldPersistGeneratedTopology(topologyFilename, topologyDescriptor, sw.toString(), gwServices)) {
log.persistingGeneratedTopology(topologyFilename);
try (OutputStream outputStream = Files.newOutputStream(topologyDescriptor.toPath());
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
BufferedWriter fw = new BufferedWriter(outputStreamWriter)) {
fw.write(sw.toString());
fw.flush();
}
} else {
log.skippingDeploymentOfGeneratedTopology(topologyFilename); // KNOX-2302
}
} catch (IOException e) {
log.failedToGenerateTopologyFromSimpleDescriptor(topologyDescriptor.getName(), e);
topologyDescriptor.delete();
}
result.put(RESULT_TOPOLOGY, topologyDescriptor);
return result;
}