Skip to content

Commit

Permalink
Add migration command for agent pre-installation
Browse files Browse the repository at this point in the history
  • Loading branch information
liam-mackie committed Feb 5, 2025
1 parent 6f300ff commit 6269c10
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 0 deletions.
9 changes: 9 additions & 0 deletions docker/kubernetes-agent-tentacle/scripts/configure-and-run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ function validateWorkerVariables() {
echo " - worker pools '$WorkerPools'"
}

function migrateFromPreinstallScript() {
tentacle migrate-preinstalled-k8s-config \
--source-config-map-name "tentacle-config-pre" \
--source-secret-name "tentacle-secret-pre" \
--destination-config-map-name "tentacle-config" \
--destination-secret-name "tentacle-secret"
}

function configureTentacle() {
tentacle create-instance --instance "$instanceName" --config "$configurationDirectory/tentacle.config" --home "$configurationDirectory"

Expand Down Expand Up @@ -424,6 +432,7 @@ else

echo "==============================================="

migrateFromPreinstallScript
configureTentacle
registerTentacle
addAdditionalServerInstancesIfRequired
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using System;
using System.Net;
using Octopus.Diagnostics;
using Octopus.Tentacle.Startup;
using k8s;
using k8s.Autorest;
using Octopus.Tentacle.Kubernetes;

namespace Octopus.Tentacle.Commands
{
public class MigratePreInstalledKubernetesDeploymentTargetCommand : AbstractCommand
{
readonly ISystemLog log;
readonly IKubernetesClientConfigProvider configProvider;

string? sourceConfigMapName;
string? sourceSecretName;
string? destinationConfigMapName;
string? destinationSecretName;

public MigratePreInstalledKubernetesDeploymentTargetCommand(IKubernetesClientConfigProvider configProvider, ISystemLog log, ILogFileOnlyLogger logFileOnlyLogger) : base(logFileOnlyLogger)
{
this.log = log;
this.configProvider = configProvider;

Options.Add("source-config-map-name=", "The name of the source config map (created by the pre-installation of the agent)", v => sourceConfigMapName = v);
Options.Add("source-secret-name=", "The name of the source secret (created by the pre-installation of the agent)", v => sourceSecretName = v);
Options.Add("destination-config-map-name=", "The name of the destination config map", v => destinationConfigMapName = v);
Options.Add("destination-secret-name=", "The name of the destination secret", v => destinationSecretName = v);
}

// This command is only used as a way to programatically copy the config map and secret from the pre-installation hook to the new agent
// It does not access tentacle configuration so that it doesn't
protected override void Start()
{
// Check that the sources and destinations are different
if (sourceSecretName == destinationSecretName || sourceConfigMapName == destinationConfigMapName)
{
log.Error("Source and destination names must be different.");
return;
}

var config = configProvider.Get();
var client = new k8s.Kubernetes(config);

// Check that the sources exist
var sourceConfigMap = TryGetCoreV1Object(() => client.CoreV1.ReadNamespacedConfigMap(sourceConfigMapName, KubernetesConfig.Namespace));
var sourceSecret = TryGetCoreV1Object(() => client.CoreV1.ReadNamespacedSecret(sourceSecretName, KubernetesConfig.Namespace));
if (sourceConfigMap is null || sourceSecret is null)
{
log.Info("Source config map or secret not found, skipping migration.");
return;
}

// Check if the destinations exist
var destinationConfigMap = TryGetCoreV1Object(() => client.CoreV1.ReadNamespacedConfigMap(destinationConfigMapName, KubernetesConfig.Namespace));
var destinationSecret = TryGetCoreV1Object(() => client.CoreV1.ReadNamespacedSecret(destinationSecretName, KubernetesConfig.Namespace));
if (destinationConfigMap is null || destinationSecret is null)
{
log.Info("destination config map or secret not found, skipping migration.");
return;
}


// Check if the destination is already registered
if (destinationConfigMap.Data is not null && destinationConfigMap.Data.TryGetValue("Tentacle.Services.IsRegistered", out var isRegistered) && isRegistered == "True")
{
log.Info("Tentacle is already registered, skipping registration.");
return;
}

// Copy the data from the source to the destination
destinationConfigMap.Data = sourceConfigMap.Data;
destinationSecret.Data = sourceSecret.Data;
client.CoreV1.ReplaceNamespacedConfigMap(destinationConfigMap, destinationConfigMapName, KubernetesConfig.Namespace);
client.CoreV1.ReplaceNamespacedSecret(destinationSecret, destinationSecretName, KubernetesConfig.Namespace);

// Delete the sources (they are no longer needed)
client.CoreV1.DeleteNamespacedConfigMap(sourceConfigMapName, KubernetesConfig.Namespace);
client.CoreV1.DeleteNamespacedSecret(sourceSecretName, KubernetesConfig.Namespace);

log.Info("Migration complete.");
}

T? TryGetCoreV1Object<T>(Func<T> kubernetesFunc) where T : class
{
try
{
return kubernetesFunc();
}
catch (HttpOperationException ex) when (ex.Response.StatusCode == HttpStatusCode.NotFound)
{
return null;
}
}
}


}
1 change: 1 addition & 0 deletions source/Octopus.Tentacle/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public override IContainer BuildContainer(StartUpInstanceRequest startUpInstance
#pragma warning restore CS0618 // Type or member is obsolete
builder.RegisterCommand<RegisterKubernetesDeploymentTargetCommand>("register-k8s-target", "Registers this kubernetes agent as a deployment target with an Octopus Server");
builder.RegisterCommand<RegisterKubernetesWorkerCommand>("register-k8s-worker", "Registers this kubernetes agent as a worker with an Octopus Server");
builder.RegisterCommand<MigratePreInstalledKubernetesDeploymentTargetCommand>("migrate-preinstalled-k8s-config", "Migrates the configuration from the pre-install hook to the running agent instance");
builder.RegisterCommand<ExtractCommand>("extract", "Extracts a NuGet package");
builder.RegisterCommand<DeregisterMachineCommand>("deregister-from", "Deregisters this deployment target from an Octopus Server");
builder.RegisterCommand<DeregisterWorkerCommand>("deregister-worker", "Deregisters this worker from an Octopus Server");
Expand Down

0 comments on commit 6269c10

Please sign in to comment.