Skip to content

Commit 004d1f5

Browse files
committed
Add helm chart generation
1 parent a093ad2 commit 004d1f5

File tree

9 files changed

+218
-3
lines changed

9 files changed

+218
-3
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,3 +348,5 @@ MigrationBackup/
348348

349349
# Ionide (cross platform F# VS Code tools) working folder
350350
.ionide/
351+
352+
.DS_Store

src/Opulence/HelmChartStep.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Opulence
2+
{
3+
public sealed class HelmChartStep : Step
4+
{
5+
public override string DisplayName => "Helm";
6+
}
7+
}

src/Opulence/StepCollection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ namespace Opulence
44
{
55
public sealed class StepCollection : Collection<Step>
66
{
7-
public T? GetT<T>() where T : Step
7+
public T? Get<T>() where T : Step
88
{
99
for (var i = 0; i < Count; i++)
1010
{

src/dotnet-opulence/DirectoryCopy.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.IO;
2+
3+
namespace Opulence
4+
{
5+
public static class DirectoryCopy
6+
{
7+
public static void Copy(string source, string destination)
8+
{
9+
CopyCore(new DirectoryInfo(source), new DirectoryInfo(destination));
10+
}
11+
12+
private static void CopyCore(DirectoryInfo source, DirectoryInfo destination)
13+
{
14+
Directory.CreateDirectory(destination.FullName);
15+
16+
foreach (var file in source.GetFiles())
17+
{
18+
file.CopyTo(Path.Combine(destination.FullName, file.Name), true);
19+
}
20+
21+
foreach (var nextSource in source.GetDirectories())
22+
{
23+
var nextDestination = destination.CreateSubdirectory(nextSource.Name);
24+
CopyCore(nextSource, nextDestination);
25+
}
26+
}
27+
}
28+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using System;
2+
using System.CommandLine;
3+
using System.CommandLine.Invocation;
4+
using System.IO;
5+
using System.Threading.Tasks;
6+
7+
namespace Opulence
8+
{
9+
internal static class HelmChartGenerator
10+
{
11+
public static async Task GenerateAsync(IConsole console, Application application, ContainerStep container, HelmChartStep chart, string outputDirectoryPath)
12+
{
13+
var directoryPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
14+
var chartDirectoryPath = Path.Combine(directoryPath, application.Name.ToLowerInvariant());
15+
16+
try
17+
{
18+
Directory.CreateDirectory(directoryPath);
19+
Directory.CreateDirectory(chartDirectoryPath);
20+
21+
var templateDirectoryPath = Path.Combine(
22+
Path.GetDirectoryName(typeof(HelmChartGenerator).Assembly.Location)!,
23+
"Templates",
24+
"Helm");
25+
26+
DirectoryCopy.Copy(templateDirectoryPath, chartDirectoryPath);
27+
28+
// Write Chart.yaml
29+
//
30+
// apiVersion: v1
31+
// name: <appname>
32+
// version: <version>
33+
// appVersion: <version>
34+
File.WriteAllLines(Path.Combine(chartDirectoryPath, "Chart.yaml"), new[]
35+
{
36+
$"apiVersion: v1",
37+
$"name: {application.Name.ToLowerInvariant()}",
38+
$"version: {application.Version.Replace('+', '-')}",
39+
$"appVersion: {application.Version.Replace('+', '-')}"
40+
});
41+
42+
// Write values.yaml
43+
//
44+
// image:
45+
// repository: rynowak.azurecr.io/rochambot/gamemaster
46+
File.WriteAllLines(Path.Combine(chartDirectoryPath, "values.yaml"), new[]
47+
{
48+
$"image:",
49+
$" repository: {container.ImageName}",
50+
});
51+
52+
console.Out.WriteLine("Packaging Helm Chart...");
53+
54+
await Process.ExecuteAsync(
55+
"helm",
56+
$"package . -d {outputDirectoryPath}",
57+
workingDir: chartDirectoryPath,
58+
stdOut: o =>
59+
{
60+
console.SetTerminalForeground(ConsoleColor.Gray);
61+
console.Out.WriteLine("\t" + o);
62+
console.ResetTerminalForegroundColor();
63+
},
64+
stdErr: o =>
65+
{
66+
console.SetTerminalForeground(ConsoleColor.Red);
67+
console.Error.WriteLine("\t" + o);
68+
console.ResetTerminalForegroundColor();
69+
});
70+
}
71+
finally
72+
{
73+
Directory.Delete(directoryPath, recursive: true);
74+
}
75+
}
76+
}
77+
}

src/dotnet-opulence/PackageCommandHandler.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.CommandLine;
33
using System.CommandLine.Invocation;
4-
using System.ComponentModel;
54
using System.IO;
65
using System.Linq;
76
using System.Text;
@@ -48,6 +47,10 @@ public static async Task ExecuteAsync(IConsole console, string projectFilePath)
4847
{
4948
await BuildContainerImageAsync(console, application, container);
5049
}
50+
else if (step is HelmChartStep chart)
51+
{
52+
await BuildHelmChartAsync(console, application, application.Steps.Get<ContainerStep>()!, chart);
53+
}
5154
}
5255
catch (ApplicationException ex)
5356
{
@@ -71,10 +74,11 @@ private static async Task<Application> InitializeApplicationAsync(IConsole conso
7174
var application = new Application()
7275
{
7376
Name = Path.GetFileNameWithoutExtension(projectFilePath),
74-
ProjectFilePath = projectFilePath,
77+
ProjectFilePath = Path.GetFullPath(projectFilePath),
7578
Steps =
7679
{
7780
new ContainerStep(),
81+
new HelmChartStep(),
7882
},
7983
};
8084

@@ -242,6 +246,12 @@ private static void ApplyContainerDefaults(Application application, ContainerSte
242246
container.ImageTag ??= application.Version.Replace("+", "-");
243247
}
244248

249+
private static Task BuildHelmChartAsync(IConsole console, Application application, ContainerStep container, HelmChartStep chart)
250+
{
251+
var outputDirectoryPath = Path.Combine(Path.GetDirectoryName(application.ProjectFilePath)!, "bin");
252+
return HelmChartGenerator.GenerateAsync(console, application, container, chart, outputDirectoryPath);
253+
}
254+
245255
public class PackageGlobals
246256
{
247257
public Application? App;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{{/* vim: set filetype=mustache: */}}
2+
{{/*
3+
Expand the name of the chart.
4+
*/}}
5+
{{- define "thischart.name" -}}
6+
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
7+
{{- end -}}
8+
9+
{{/*
10+
Create a default fully qualified app name.
11+
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
12+
If release name contains chart name it will be used as a full name.
13+
*/}}
14+
{{- define "thischart.fullname" -}}
15+
{{- if .Values.fullnameOverride -}}
16+
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
17+
{{- else -}}
18+
{{- $name := default .Chart.Name .Values.nameOverride -}}
19+
{{- if contains $name .Release.Name -}}
20+
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
21+
{{- else -}}
22+
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
23+
{{- end -}}
24+
{{- end -}}
25+
{{- end -}}
26+
27+
{{/*
28+
Create chart name and version as used by the chart label.
29+
*/}}
30+
{{- define "thischart.chart" -}}
31+
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
32+
{{- end -}}
33+
34+
{{/*
35+
Common labels
36+
*/}}
37+
{{- define "thischart.labels" -}}
38+
app.kubernetes.io/name: {{ include "thischart.name" . }}
39+
helm.sh/chart: {{ include "thischart.chart" . }}
40+
app.kubernetes.io/instance: {{ .Release.Name }}
41+
{{- if .Chart.AppVersion }}
42+
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
43+
{{- end }}
44+
app.kubernetes.io/managed-by: {{ .Release.Service }}
45+
{{- end -}}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: {{ include "thischart.fullname" . }}
5+
labels:
6+
{{ include "thischart.labels" . | indent 4 }}
7+
spec:
8+
replicas: 1
9+
selector:
10+
matchLabels:
11+
app.kubernetes.io/name: {{ include "thischart.name" . }}
12+
app.kubernetes.io/instance: {{ .Release.Name }}
13+
template:
14+
metadata:
15+
labels:
16+
app.kubernetes.io/name: {{ include "thischart.name" . }}
17+
app.kubernetes.io/instance: {{ .Release.Name }}
18+
spec:
19+
containers:
20+
- name: {{ .Chart.Name }}
21+
image: {{ .Values.image.repository }}:{{ .Chart.AppVersion }}
22+
imagePullPolicy: Always
23+
livenessProbe:
24+
httpGet:
25+
path: /healthz
26+
port: 80
27+
initialDelaySeconds: 5
28+
periodSeconds: 5
29+
ports:
30+
- containerPort: 80
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
kind: Service
2+
apiVersion: v1
3+
metadata:
4+
name: {{ include "thischart.name" . }}
5+
labels:
6+
app.kubernetes.io/name: {{ include "thischart.name" . }}
7+
app.kubernetes.io/instance: {{ .Release.Name }}
8+
spec:
9+
selector:
10+
app.kubernetes.io/name: {{ include "thischart.name" . }}
11+
app.kubernetes.io/instance: {{ .Release.Name }}
12+
ports:
13+
- name: http
14+
protocol: TCP
15+
port: 80
16+
type: LoadBalancer

0 commit comments

Comments
 (0)