Browse Source

Refactore kubernetes manifest generator (#810)

* removed one intend

* changed 0 <= into == 0 because it can not be less then zero see also #786 for more informations

* added newline looks nicer

* removed intend if

* use of initalizes

* check for not null

* removed if nesteding

* check for null

* check for null

* remove if nesting

* added initializer

* use of language feature destruction key value

* removed unused () brakes

* use of switch statment instend of if
finitereality/replica-status-colors
Marvin Huber 6 years ago
committed by GitHub
parent
commit
d11e807456
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 224
      src/Microsoft.Tye.Core/KubernetesManifestGenerator.cs

224
src/Microsoft.Tye.Core/KubernetesManifestGenerator.cs

@ -42,71 +42,73 @@ namespace Microsoft.Tye
var spec = new YamlMappingNode(); var spec = new YamlMappingNode();
root.Add("spec", spec); root.Add("spec", spec);
if (ingress.Rules.Count > 0) if (ingress.Rules.Count == 0)
{ {
var rules = new YamlSequenceNode(); return new KubernetesIngressOutput(ingress.Name, new YamlDocument(root));
spec.Add("rules", rules); }
// k8s ingress is grouped by host first, then grouped by path var rules = new YamlSequenceNode();
foreach (var hostgroup in ingress.Rules.GroupBy(r => r.Host)) spec.Add("rules", rules);
{
var rule = new YamlMappingNode();
rules.Add(rule);
if (!string.IsNullOrEmpty(hostgroup.Key)) // k8s ingress is grouped by host first, then grouped by path
{ foreach (var hostgroup in ingress.Rules.GroupBy(r => r.Host))
rule.Add("host", hostgroup.Key); {
} var rule = new YamlMappingNode();
rules.Add(rule);
var http = new YamlMappingNode(); if (!string.IsNullOrEmpty(hostgroup.Key))
rule.Add("http", http); {
rule.Add("host", hostgroup.Key);
}
var paths = new YamlSequenceNode(); var http = new YamlMappingNode();
http.Add("paths", paths); rule.Add("http", http);
foreach (var ingressRule in hostgroup) var paths = new YamlSequenceNode();
{ http.Add("paths", paths);
var path = new YamlMappingNode();
paths.Add(path);
var backend = new YamlMappingNode(); foreach (var ingressRule in hostgroup)
path.Add("backend", backend); {
backend.Add("serviceName", ingressRule.Service); var path = new YamlMappingNode();
paths.Add(path);
var service = application.Services.FirstOrDefault(s => s.Name == ingressRule.Service); var backend = new YamlMappingNode();
if (service is null) path.Add("backend", backend);
{ backend.Add("serviceName", ingressRule.Service);
throw new InvalidOperationException($"Could not resolve service '{ingressRule.Service}'.");
}
var binding = service.Bindings.FirstOrDefault(b => b.Name is null || b.Name == "http"); var service = application.Services.FirstOrDefault(s => s.Name == ingressRule.Service);
if (binding is null) if (service is null)
{ {
throw new InvalidOperationException($"Could not resolve an http binding for service '{service.Name}'."); throw new InvalidOperationException($"Could not resolve service '{ingressRule.Service}'.");
} }
backend.Add("servicePort", (binding.Port ?? 80).ToString(CultureInfo.InvariantCulture)); var binding = service.Bindings.FirstOrDefault(b => b.Name is null || b.Name == "http");
if (binding is null)
{
throw new InvalidOperationException($"Could not resolve an http binding for service '{service.Name}'.");
}
// Tye implements path matching similar to this example: backend.Add("servicePort", (binding.Port ?? 80).ToString(CultureInfo.InvariantCulture));
// https://kubernetes.github.io/ingress-nginx/examples/rewrite/
// // Tye implements path matching similar to this example:
// Therefore our rewrite-target is set to $2 - we want to make sure we have // https://kubernetes.github.io/ingress-nginx/examples/rewrite/
// two capture groups. //
if (string.IsNullOrEmpty(ingressRule.Path) || ingressRule.Path == "/") // Therefore our rewrite-target is set to $2 - we want to make sure we have
// two capture groups.
if (string.IsNullOrEmpty(ingressRule.Path) || ingressRule.Path == "/")
{
path.Add("path", "/()(.*)"); // () is an empty capture group.
}
else
{
if (ingressRule.PreservePath)
{ {
path.Add("path", "/()(.*)"); // () is an empty capture group. path.Add("path", $"/()({ingressRule.Path.Trim('/')}.*)");
} }
else else
{ {
if (ingressRule.PreservePath) var regex = $"{ingressRule.Path.TrimEnd('/')}(/|$)(.*)";
{ path.Add("path", regex);
path.Add("path", $"/()({ingressRule.Path.Trim('/')}.*)");
}
else
{
var regex = $"{ingressRule.Path.TrimEnd('/')}(/|$)(.*)";
path.Add("path", regex);
}
} }
} }
} }
@ -182,16 +184,18 @@ namespace Microsoft.Tye
continue; continue;
} }
if (binding.Port != null) if (binding.Port == null)
{ {
var port = new YamlMappingNode(); continue;
ports.Add(port);
port.Add("name", binding.Name ?? binding.Protocol ?? "http");
port.Add("protocol", "TCP"); // we use assume TCP. YOLO
port.Add("port", binding.Port.Value.ToString());
port.Add("targetPort", (binding.ContainerPort ?? binding.Port.Value).ToString());
} }
var port = new YamlMappingNode();
ports.Add(port);
port.Add("name", binding.Name ?? binding.Protocol ?? "http");
port.Add("protocol", "TCP"); // we use assume TCP. YOLO
port.Add("port", binding.Port.Value.ToString());
port.Add("targetPort", (binding.ContainerPort ?? binding.Port.Value).ToString());
} }
return new KubernetesServiceOutput(project.Name, new YamlDocument(root)); return new KubernetesServiceOutput(project.Name, new YamlDocument(root));
@ -205,10 +209,11 @@ namespace Microsoft.Tye
{ {
var bindings = project.Outputs.OfType<ComputedBindings>().FirstOrDefault(); var bindings = project.Outputs.OfType<ComputedBindings>().FirstOrDefault();
var root = new YamlMappingNode(); var root = new YamlMappingNode
{
root.Add("kind", "Deployment"); {"kind", "Deployment"},
root.Add("apiVersion", "apps/v1"); {"apiVersion", "apps/v1"}
};
var metadata = new YamlMappingNode(); var metadata = new YamlMappingNode();
root.Add("metadata", metadata); root.Add("metadata", metadata);
@ -343,7 +348,7 @@ namespace Microsoft.Tye
}); });
} }
if (bindings is object) if (bindings != null)
{ {
AddEnvironmentVariablesForComputedBindings(env, bindings); AddEnvironmentVariablesForComputedBindings(env, bindings);
} }
@ -377,12 +382,14 @@ namespace Microsoft.Tye
continue; continue;
} }
if (binding.Port != null) if (binding.Port == null)
{ {
var containerPort = new YamlMappingNode(); continue;
ports.Add(containerPort);
containerPort.Add("containerPort", (binding.ContainerPort ?? binding.Port.Value).ToString());
} }
var containerPort = new YamlMappingNode();
ports.Add(containerPort);
containerPort.Add("containerPort", (binding.ContainerPort ?? binding.Port.Value).ToString());
} }
} }
@ -431,48 +438,51 @@ namespace Microsoft.Tye
}); });
} }
if (sidecarBindings is object) if (sidecarBindings != null)
{ {
AddEnvironmentVariablesForComputedBindings(env, sidecarBindings); AddEnvironmentVariablesForComputedBindings(env, sidecarBindings);
} }
} }
if (project.RelocateDiagnosticsDomainSockets) if (!project.RelocateDiagnosticsDomainSockets)
{ {
// volumeMounts: continue;
// - name: shared-data
// mountPath: /usr/share/nginx/html
var volumeMounts = new YamlSequenceNode();
container.Add("volumeMounts", volumeMounts);
var volumeMount = new YamlMappingNode();
volumeMounts.Add(volumeMount);
volumeMount.Add("name", "tye-diagnostics");
volumeMount.Add("mountPath", "/var/tye/diagnostics");
} }
// volumeMounts:
// - name: shared-data
// mountPath: /usr/share/nginx/html
var volumeMounts = new YamlSequenceNode();
container.Add("volumeMounts", volumeMounts);
var volumeMount = new YamlMappingNode();
volumeMounts.Add(volumeMount);
volumeMount.Add("name", "tye-diagnostics");
volumeMount.Add("mountPath", "/var/tye/diagnostics");
} }
if (project.RelocateDiagnosticsDomainSockets) if (!project.RelocateDiagnosticsDomainSockets)
{ {
// volumes: return new KubernetesDeploymentOutput(project.Name, new YamlDocument(root));
// - name: shared-data
// emptyDir: {}
var volumes = new YamlSequenceNode();
spec.Add("volumes", volumes);
var volume = new YamlMappingNode();
volumes.Add(volume);
volume.Add("name", "tye-diagnostics");
volume.Add("emptyDir", new YamlMappingNode());
} }
// volumes:
// - name: shared-data
// emptyDir: {}
var volumes = new YamlSequenceNode();
spec.Add("volumes", volumes);
var volume = new YamlMappingNode();
volumes.Add(volume);
volume.Add("name", "tye-diagnostics");
volume.Add("emptyDir", new YamlMappingNode());
return new KubernetesDeploymentOutput(project.Name, new YamlDocument(root)); return new KubernetesDeploymentOutput(project.Name, new YamlDocument(root));
} }
private static void AddProbe(ServiceBuilder service, YamlMappingNode container, ProbeBuilder builder, string name) private static void AddProbe(ServiceBuilder service, YamlMappingNode container, ProbeBuilder builder, string probeName)
{ {
var probe = new YamlMappingNode(); var probe = new YamlMappingNode();
container.Add(name, probe); container.Add(probeName, probe);
if (builder.Http != null) if (builder.Http != null)
{ {
@ -511,11 +521,13 @@ namespace Microsoft.Tye
var headers = new YamlSequenceNode(); var headers = new YamlSequenceNode();
httpGet.Add("httpHeaders", headers); httpGet.Add("httpHeaders", headers);
foreach (var builderHeader in builderHttp.Headers) foreach (var (name, value) in builderHttp.Headers)
{ {
var header = new YamlMappingNode(); var header = new YamlMappingNode
header.Add("name", builderHeader.Key); {
header.Add("value", builderHeader.Value.ToString()!); {"name", name},
{"value", value.ToString()!}
};
headers.Add(header); headers.Add(header);
} }
} }
@ -531,7 +543,7 @@ namespace Microsoft.Tye
{ {
foreach (var binding in bindings.Bindings.OfType<EnvironmentVariableInputBinding>()) foreach (var binding in bindings.Bindings.OfType<EnvironmentVariableInputBinding>())
{ {
env.Add(new YamlMappingNode() env.Add(new YamlMappingNode
{ {
{ "name", binding.Name }, { "name", binding.Name },
{ "value", new YamlScalarNode(binding.Value) { Style = ScalarStyle.SingleQuoted, } }, { "value", new YamlScalarNode(binding.Value) { Style = ScalarStyle.SingleQuoted, } },
@ -546,16 +558,16 @@ namespace Microsoft.Tye
// name: mysecret // name: mysecret
// key: username // key: username
if (binding is SecretConnectionStringInputBinding connectionStringBinding) switch (binding)
{
AddSecret(env, connectionStringBinding.KeyName, binding.Name, "connectionstring");
}
else if (binding is SecretUrlInputBinding urlBinding)
{ {
AddSecret(env, $"{urlBinding.KeyNameBase}__PROTOCOL", binding.Name, "protocol"); case SecretConnectionStringInputBinding connectionStringBinding:
AddSecret(env, $"{urlBinding.KeyNameBase}__HOST", binding.Name, "host"); AddSecret(env, connectionStringBinding.KeyName, binding.Name, "connectionstring");
AddSecret(env, $"{urlBinding.KeyNameBase}__PORT", binding.Name, "port"); break;
case SecretUrlInputBinding urlBinding:
AddSecret(env, $"{urlBinding.KeyNameBase}__PROTOCOL", binding.Name, "protocol");
AddSecret(env, $"{urlBinding.KeyNameBase}__HOST", binding.Name, "host");
AddSecret(env, $"{urlBinding.KeyNameBase}__PORT", binding.Name, "port");
break;
} }
} }

Loading…
Cancel
Save