From edaed466f49cbe6e9a11b3e92377c2bd5c317a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BChler?= Date: Fri, 6 Oct 2023 08:27:16 +0200 Subject: [PATCH] feat(operator): add build targets extension for automatic resource generation BREAKING CHANGE: The targets file contains other properties than before. Refer to the documentation for explicit details. --- .config/dotnet-tools.json | 4 +- _old/src/KubeOps/Build/KubeOps.targets | 111 ------------------ .../Commands/Generators/InstallerGenerator.cs | 75 ------------ examples/.gitignore | 2 + .../Controller/V1SecondEntityController.cs | 3 +- examples/Operator/todos.txt | 2 - src/KubeOps.Cli/Arguments.cs | 4 + .../Commands/Generator/CrdGenerator.cs | 4 +- .../Generator/{Generator.cs => Generate.cs} | 5 +- .../Commands/Generator/InstallerGenerator.cs | 68 +++++++++++ .../Commands/Generator/RbacGenerator.cs | 1 - src/KubeOps.Cli/Program.cs | 2 +- .../Properties/launchSettings.json | 9 +- src/KubeOps.Operator/Build/Generator.targets | 79 +++++++++++++ src/KubeOps.Operator/KubeOps.Operator.csproj | 6 + 15 files changed, 174 insertions(+), 201 deletions(-) delete mode 100644 _old/src/KubeOps/Build/KubeOps.targets delete mode 100644 _old/src/KubeOps/Operator/Commands/Generators/InstallerGenerator.cs create mode 100644 examples/.gitignore rename src/KubeOps.Cli/Commands/Generator/{Generator.cs => Generate.cs} (75%) create mode 100644 src/KubeOps.Cli/Commands/Generator/InstallerGenerator.cs create mode 100644 src/KubeOps.Operator/Build/Generator.targets diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 073ba815..6146d3b7 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -4,9 +4,7 @@ "tools": { "docfx": { "version": "2.71.0", - "commands": [ - "docfx" - ] + "commands": ["docfx"] } } } diff --git a/_old/src/KubeOps/Build/KubeOps.targets b/_old/src/KubeOps/Build/KubeOps.targets deleted file mode 100644 index c9087a39..00000000 --- a/_old/src/KubeOps/Build/KubeOps.targets +++ /dev/null @@ -1,111 +0,0 @@ - - - - - $(MSBuildProjectDirectory) - - - - - $(KubeOpsBasePath)\config - - - - - $(KubeOpsBasePath)\Dockerfile - latest - - - - - $(KubeOpsConfigRoot)\crds - Yaml - false - - - - - $(KubeOpsConfigRoot)\rbac - Yaml - - - - - $(KubeOpsConfigRoot)\operator - Yaml - - - - - $(KubeOpsConfigRoot)\install - Yaml - - - - - - %(IntermediateAssembly.ModifiedTime) - - - - - - %(IntermediateAssembly.ModifiedTime) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/_old/src/KubeOps/Operator/Commands/Generators/InstallerGenerator.cs b/_old/src/KubeOps/Operator/Commands/Generators/InstallerGenerator.cs deleted file mode 100644 index a866e727..00000000 --- a/_old/src/KubeOps/Operator/Commands/Generators/InstallerGenerator.cs +++ /dev/null @@ -1,75 +0,0 @@ -using k8s.Models; - -using KubeOps.Operator.Commands.CommandHelpers; -using KubeOps.Operator.Entities.Kustomize; -using KubeOps.Operator.Serialization; - -using McMaster.Extensions.CommandLineUtils; - -namespace KubeOps.Operator.Commands.Generators; - -[Command("installer", Description = "Generates kustomization YAML for installing the entire operator.")] -internal class InstallerGenerator : OutputBase -{ - private readonly OperatorSettings _settings; - - public InstallerGenerator(OperatorSettings settings) => _settings = settings; - - [Option("--crds-dir", Description = "The path where the CRD YAML files are located.")] - public string CrdsPath { get; set; } = "../crds"; - - [Option("--rbac-dir", Description = "The path where the RBAC YAML files are located.")] - public string RbacPath { get; set; } = "../rbac"; - - [Option("--operator-dir", Description = "The path where the operator YAML files are located.")] - public string OperatorPath { get; set; } = "../operator"; - - [Option("--image-name", Description = "The name of the operator's Docker image.")] - public string ImageName { get; set; } = "public-docker-image-path"; - - [Option("--image-tag", Description = "The tag for the Docker image.")] - public string ImageTag { get; set; } = "latest"; - - public async Task OnExecuteAsync(CommandLineApplication app) - { - var fileWriter = new FileWriter(app.Out); - fileWriter.Add( - $"namespace.{Format.ToString().ToLower()}", - EntitySerializer.Serialize( - new V1Namespace( - V1Namespace.KubeApiVersion, - V1Namespace.KubeKind, - new V1ObjectMeta(name: "system")), - Format)); - fileWriter.Add( - $"kustomization.{Format.ToString().ToLower()}", - EntitySerializer.Serialize( - new KustomizationConfig - { - NamePrefix = $"{_settings.Name}-", - Namespace = $"{_settings.Name}-system", - CommonLabels = new Dictionary { { "operator", _settings.Name }, }, - Resources = new List - { - $"./namespace.{Format.ToString().ToLower()}", - OutputPath == null - ? CrdsPath - : Path.GetRelativePath(OutputPath, CrdsPath).Replace('\\', '/'), - OutputPath == null - ? RbacPath - : Path.GetRelativePath(OutputPath, RbacPath).Replace('\\', '/'), - OutputPath == null - ? OperatorPath - : Path.GetRelativePath(OutputPath, OperatorPath).Replace('\\', '/'), - }, - Images = new List - { - new() { Name = "operator", NewName = ImageName, NewTag = ImageTag, }, - }, - }, - Format)); - - await fileWriter.OutputAsync(OutputPath); - return ExitCodes.Success; - } -} diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 00000000..67bea2c5 --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,2 @@ +config/ +Dockerfile diff --git a/examples/Operator/Controller/V1SecondEntityController.cs b/examples/Operator/Controller/V1SecondEntityController.cs index afe84391..8b121647 100644 --- a/examples/Operator/Controller/V1SecondEntityController.cs +++ b/examples/Operator/Controller/V1SecondEntityController.cs @@ -23,8 +23,9 @@ public V1SecondEntityController( _logger = logger; } - public async Task ReconcileAsync(V1SecondEntity entity) + public Task ReconcileAsync(V1SecondEntity entity) { _logger.LogInformation("Reconciling entity {Entity}.", entity); + return Task.CompletedTask; } } diff --git a/examples/Operator/todos.txt b/examples/Operator/todos.txt index b2dcd672..bc87ef49 100644 --- a/examples/Operator/todos.txt +++ b/examples/Operator/todos.txt @@ -1,6 +1,4 @@ todo: -- other CLI commands -- build targets - error handling - web: webhooks - docs diff --git a/src/KubeOps.Cli/Arguments.cs b/src/KubeOps.Cli/Arguments.cs index 12d768bc..1c01050d 100644 --- a/src/KubeOps.Cli/Arguments.cs +++ b/src/KubeOps.Cli/Arguments.cs @@ -41,4 +41,8 @@ var slnFile "namespace", () => "default", "The Kubernetes namespace that the operator will be run."); + + public static readonly Argument OperatorName = new( + "name", + "Name of the operator."); } diff --git a/src/KubeOps.Cli/Commands/Generator/CrdGenerator.cs b/src/KubeOps.Cli/Commands/Generator/CrdGenerator.cs index 1969e7e8..9aad5019 100644 --- a/src/KubeOps.Cli/Commands/Generator/CrdGenerator.cs +++ b/src/KubeOps.Cli/Commands/Generator/CrdGenerator.cs @@ -16,7 +16,7 @@ public static Command Command { get { - var cmd = new Command("crd", "Generates CRDs for Kubernetes based on a solution or project.") + var cmd = new Command("crds", "Generates CRDs for Kubernetes based on a solution or project.") { Options.OutputFormat, Options.OutputPath, @@ -24,8 +24,6 @@ public static Command Command Options.TargetFramework, Arguments.SolutionOrProjectFile, }; - cmd.AddAlias("crds"); - cmd.AddAlias("c"); cmd.SetHandler(ctx => Handler(AnsiConsole.Console, ctx)); return cmd; diff --git a/src/KubeOps.Cli/Commands/Generator/Generator.cs b/src/KubeOps.Cli/Commands/Generator/Generate.cs similarity index 75% rename from src/KubeOps.Cli/Commands/Generator/Generator.cs rename to src/KubeOps.Cli/Commands/Generator/Generate.cs index 4a1deb70..6bb18753 100644 --- a/src/KubeOps.Cli/Commands/Generator/Generator.cs +++ b/src/KubeOps.Cli/Commands/Generator/Generate.cs @@ -3,17 +3,18 @@ namespace KubeOps.Cli.Commands.Generator; -internal static class Generator +internal static class Generate { public static Command Command { get { - var cmd = new Command("generator", "Generates elements related to an operator.") + var cmd = new Command("generate", "Generates elements related to an operator.") { CertificateGenerator.Command, CrdGenerator.Command, DockerGenerator.Command, + InstallerGenerator.Command, OperatorGenerator.Command, RbacGenerator.Command, }; diff --git a/src/KubeOps.Cli/Commands/Generator/InstallerGenerator.cs b/src/KubeOps.Cli/Commands/Generator/InstallerGenerator.cs new file mode 100644 index 00000000..2c288f7d --- /dev/null +++ b/src/KubeOps.Cli/Commands/Generator/InstallerGenerator.cs @@ -0,0 +1,68 @@ +using System.CommandLine; +using System.CommandLine.Invocation; + +using k8s; +using k8s.Models; + +using KubeOps.Abstractions.Kustomize; +using KubeOps.Cli.Output; + +using Spectre.Console; + +namespace KubeOps.Cli.Commands.Generator; + +internal static class InstallerGenerator +{ + public static Command Command + { + get + { + var cmd = new Command("installer", "Generates Kustomization YAML to install the entire operator.") + { + Options.OutputPath, Options.OutputFormat, Arguments.OperatorName, + }; + cmd.SetHandler(ctx => Handler(AnsiConsole.Console, ctx)); + + return cmd; + } + } + + internal static async Task Handler(IAnsiConsole console, InvocationContext ctx) + { + var outPath = ctx.ParseResult.GetValueForOption(Options.OutputPath); + var format = ctx.ParseResult.GetValueForOption(Options.OutputFormat); + var name = ctx.ParseResult.GetValueForArgument(Arguments.OperatorName); + + var result = new ResultOutput(console, format); + console.WriteLine("Generate operator installer."); + + result.Add( + $"namespace.{format.ToString().ToLowerInvariant()}", + new V1Namespace(metadata: new(name: "system")).Initialize()); + result.Add( + $"kustomization.{format.ToString().ToLowerInvariant()}", + new KustomizationConfig + { + NamePrefix = $"{name}-", + Namespace = $"{name}-system", + CommonLabels = new Dictionary { { "operator", name }, }, + Resources = new List + { + $"./namespace.{format.ToString().ToLowerInvariant()}", "./rbac", "./operator", "./crds", + }, + Images = new List + { + new() { Name = "operator", NewName = "accessible-docker-image", NewTag = "latest", }, + }, + }); + + if (outPath is not null) + { + await result.Write(outPath); + } + else + { + result.Write(); + } + } +} diff --git a/src/KubeOps.Cli/Commands/Generator/RbacGenerator.cs b/src/KubeOps.Cli/Commands/Generator/RbacGenerator.cs index 0a0b921a..ddd4450c 100644 --- a/src/KubeOps.Cli/Commands/Generator/RbacGenerator.cs +++ b/src/KubeOps.Cli/Commands/Generator/RbacGenerator.cs @@ -28,7 +28,6 @@ public static Command Command Options.TargetFramework, Arguments.SolutionOrProjectFile, }; - cmd.AddAlias("r"); cmd.SetHandler(ctx => Handler(AnsiConsole.Console, ctx)); return cmd; diff --git a/src/KubeOps.Cli/Program.cs b/src/KubeOps.Cli/Program.cs index ecb61454..91c92f09 100644 --- a/src/KubeOps.Cli/Program.cs +++ b/src/KubeOps.Cli/Program.cs @@ -13,7 +13,7 @@ return await new CommandLineBuilder(new RootCommand( "CLI for KubeOps. Commandline tool to help with management tasks such as generating or installing CRDs.") { - Generator.Command, Version.Command, Install.Command, Uninstall.Command, + Generate.Command, Version.Command, Install.Command, Uninstall.Command, }) .UseDefaults() .UseParseErrorReporting(ExitCodes.UsageError) diff --git a/src/KubeOps.Cli/Properties/launchSettings.json b/src/KubeOps.Cli/Properties/launchSettings.json index e72b6b33..8c5bb69a 100644 --- a/src/KubeOps.Cli/Properties/launchSettings.json +++ b/src/KubeOps.Cli/Properties/launchSettings.json @@ -4,7 +4,7 @@ "CLI Generate RBAC": { "commandName": "Project", "workingDirectory": "$(ProjectDir)", - "commandLineArgs": "gen rbac ../../examples/Operator/Operator.csproj" + "commandLineArgs": "g rbac ../../examples/Operator/Operator.csproj" }, "CLI Generate Cert": { "commandName": "Project", @@ -14,7 +14,7 @@ "CLI Generate CRDs": { "commandName": "Project", "workingDirectory": "$(ProjectDir)", - "commandLineArgs": "g c ../../examples/Operator/Operator.csproj" + "commandLineArgs": "g crds ../../examples/Operator/Operator.csproj" }, "CLI Generate Operator": { "commandName": "Project", @@ -26,6 +26,11 @@ "workingDirectory": "$(ProjectDir)", "commandLineArgs": "g docker" }, + "CLI Generate Installer": { + "commandName": "Project", + "workingDirectory": "$(ProjectDir)", + "commandLineArgs": "g installer demo-operator" + }, "CLI Install": { "commandName": "Project", "workingDirectory": "$(ProjectDir)", diff --git a/src/KubeOps.Operator/Build/Generator.targets b/src/KubeOps.Operator/Build/Generator.targets new file mode 100644 index 00000000..61d1ade5 --- /dev/null +++ b/src/KubeOps.Operator/Build/Generator.targets @@ -0,0 +1,79 @@ + + + + $(AssemblyName.ToLowerInvariant()) + dotnet kubeops + $(MSBuildProjectDirectory)\config + $(MSBuildProjectDirectory) + $(KubeOpsGenRoot)\crds + $(KubeOpsGenRoot)\rbac + $(KubeOpsGenRoot)\operator + $(KubeOpsGenRoot) + + + + + + %(IntermediateAssembly.ModifiedTime) + + + + + + %(IntermediateAssembly.ModifiedTime) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/KubeOps.Operator/KubeOps.Operator.csproj b/src/KubeOps.Operator/KubeOps.Operator.csproj index f099d2ea..86d5349d 100644 --- a/src/KubeOps.Operator/KubeOps.Operator.csproj +++ b/src/KubeOps.Operator/KubeOps.Operator.csproj @@ -24,5 +24,11 @@ + + + + build/ + +