Skip to content

Commit

Permalink
Set SnapInstallData from CK8sConfigSpec (#62)
Browse files Browse the repository at this point in the history
adds option to specify channel, revision or localPath in the CK8sConfig template
  • Loading branch information
eaudetcobello authored Oct 15, 2024
1 parent 9ed3967 commit e55ca45
Show file tree
Hide file tree
Showing 12 changed files with 208 additions and 45 deletions.
14 changes: 14 additions & 0 deletions bootstrap/api/v1beta2/ck8sconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,20 @@ type CK8sConfigSpec struct {
// +optional
SnapstoreProxyID string `json:"snapstoreProxyId,omitempty"`

// Channel is the channel to use for the snap install.
// +optional
Channel string `json:"channel,omitempty"`

// Revision is the revision to use for the snap install.
// If Channel is set, this will be ignored.
// +optional
Revision string `json:"revision,omitempty"`

// LocalPath is the path of a local snap file in the workload cluster to use for the snap install.
// If Channel or Revision are set, this will be ignored.
// +optional
LocalPath string `json:"localPath,omitempty"`

// CK8sControlPlaneConfig is configuration for the control plane node.
// +optional
ControlPlaneConfig CK8sControlPlaneConfig `json:"controlPlane,omitempty"`
Expand Down
6 changes: 6 additions & 0 deletions bootstrap/api/v1beta2/condition_consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,9 @@ const (
// an error while retrieving certificates for a joining node.
CertificatesCorruptedReason = "CertificatesCorrupted"
)

const (
SnapInstallDataValidatedCondition clusterv1.ConditionType = "SnapInstallDataValidated"

SnapInstallValidationFailedReason = "SnapInstallValidationFailed"
)
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ spec:
items:
type: string
type: array
channel:
description: Channel is the channel to use for the snap install.
type: string
controlPlane:
description: CK8sControlPlaneConfig is configuration for the control
plane node.
Expand Down Expand Up @@ -192,6 +195,11 @@ spec:
the default CNI.
type: boolean
type: object
localPath:
description: |-
LocalPath is the path of a local snap file in the workload cluster to use for the snap install.
If Channel or Revision are set, this will be ignored.
type: string
nodeName:
description: |-
NodeName is the name to use for the kubelet of this node. It is needed for clouds
Expand All @@ -210,6 +218,11 @@ spec:
items:
type: string
type: array
revision:
description: |-
Revision is the revision to use for the snap install.
If Channel is set, this will be ignored.
type: string
snapstoreProxyDomain:
description: The snap store proxy domain
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ spec:
items:
type: string
type: array
channel:
description: Channel is the channel to use for the snap install.
type: string
controlPlane:
description: CK8sControlPlaneConfig is configuration for the
control plane node.
Expand Down Expand Up @@ -201,6 +204,11 @@ spec:
enable the default CNI.
type: boolean
type: object
localPath:
description: |-
LocalPath is the path of a local snap file in the workload cluster to use for the snap install.
If Channel or Revision are set, this will be ignored.
type: string
nodeName:
description: |-
NodeName is the name to use for the kubelet of this node. It is needed for clouds
Expand All @@ -219,6 +227,11 @@ spec:
items:
type: string
type: array
revision:
description: |-
Revision is the revision to use for the snap install.
If Channel is set, this will be ignored.
type: string
snapstoreProxyDomain:
description: The snap store proxy domain
type: string
Expand Down
126 changes: 98 additions & 28 deletions bootstrap/controllers/ck8sconfig_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,20 @@ func (r *CK8sConfigReconciler) joinControlplane(ctx context.Context, scope *Scop
return err
}

snapInstallData := r.resolveInPlaceUpgradeRelease(machine)
snapInstallData, err := r.getSnapInstallDataFromSpec(scope.Config.Spec)
if err != nil {
return fmt.Errorf("failed to get snap install data from spec: %w", err)
}

// If the machine has an in-place upgrade annotation, use it to set the snap install data
inPlaceInstallData := r.resolveInPlaceUpgradeRelease(machine)
if inPlaceInstallData != nil {
snapInstallData = inPlaceInstallData
}

// log snapinstalldata
scope.Info("SnapInstallData Spec", "Option", scope.Config.Spec.Channel, "Value", scope.Config.Spec.Revision, "LocalPath", scope.Config.Spec.LocalPath)
scope.Info("SnapInstallData", "Option", snapInstallData.Option, "Value", snapInstallData.Value)

input := cloudinit.JoinControlPlaneInput{
BaseUserData: cloudinit.BaseUserData{
Expand Down Expand Up @@ -343,7 +356,16 @@ func (r *CK8sConfigReconciler) joinWorker(ctx context.Context, scope *Scope) err
return err
}

snapInstallData := r.resolveInPlaceUpgradeRelease(machine)
snapInstallData, err := r.getSnapInstallDataFromSpec(scope.Config.Spec)
if err != nil {
return fmt.Errorf("failed to get snap install data from spec: %w", err)
}

// If the machine has an in-place upgrade annotation, use it to set the snap install data
inPlaceInstallData := r.resolveInPlaceUpgradeRelease(machine)
if inPlaceInstallData != nil {
snapInstallData = inPlaceInstallData
}

input := cloudinit.JoinWorkerInput{
BaseUserData: cloudinit.BaseUserData{
Expand Down Expand Up @@ -403,39 +425,83 @@ func (r *CK8sConfigReconciler) resolveFiles(ctx context.Context, cfg *bootstrapv
return collected, nil
}

func (r *CK8sConfigReconciler) resolveInPlaceUpgradeRelease(machine *clusterv1.Machine) cloudinit.SnapInstallData {
func (r *CK8sConfigReconciler) resolveInPlaceUpgradeRelease(machine *clusterv1.Machine) *cloudinit.SnapInstallData {
mAnnotations := machine.GetAnnotations()

if mAnnotations != nil {
return cloudinit.SnapInstallData{}
if mAnnotations == nil {
return nil
}

val, ok := mAnnotations[bootstrapv1.InPlaceUpgradeReleaseAnnotation]
if ok {
optionKv := strings.Split(val, "=")

switch optionKv[0] {
case "channel":
return cloudinit.SnapInstallData{
Option: cloudinit.InstallOptionChannel,
Value: optionKv[1],
}
case "revision":
return cloudinit.SnapInstallData{
Option: cloudinit.InstallOptionRevision,
Value: optionKv[1],
}
case "localPath":
return cloudinit.SnapInstallData{
Option: cloudinit.InstallOptionLocalPath,
Value: optionKv[1],
}
default:
r.Log.Info("Unknown in-place upgrade release option, ignoring", "option", optionKv[0])
if !ok {
return nil
}

optionKv := strings.Split(val, "=")

if len(optionKv) != 2 {
r.Log.Info("Invalid in-place upgrade release annotation, ignoring", "annotation", val)
return nil
}

switch optionKv[0] {
case "channel":
return &cloudinit.SnapInstallData{
Option: cloudinit.InstallOptionChannel,
Value: optionKv[1],
}
case "revision":
return &cloudinit.SnapInstallData{
Option: cloudinit.InstallOptionRevision,
Value: optionKv[1],
}
case "localPath":
return &cloudinit.SnapInstallData{
Option: cloudinit.InstallOptionLocalPath,
Value: optionKv[1],
}
default:
r.Log.Info("Unknown in-place upgrade release option, ignoring", "option", optionKv[0])
}

return nil
}

func (r *CK8sConfigReconciler) getSnapInstallDataFromSpec(spec bootstrapv1.CK8sConfigSpec) (*cloudinit.SnapInstallData, error) {
// Ensure that exactly one option is set
count := 0
if spec.Channel != "" {
count++
}
if spec.Revision != "" {
count++
}
if spec.LocalPath != "" {
count++
}
if count > 1 {
return nil, fmt.Errorf("only one of Channel, Revision, or LocalPath can be set, but multiple were provided")
}

return cloudinit.SnapInstallData{}
switch {
case spec.Channel != "":
return &cloudinit.SnapInstallData{
Option: cloudinit.InstallOptionChannel,
Value: spec.Channel,
}, nil
case spec.Revision != "":
return &cloudinit.SnapInstallData{
Option: cloudinit.InstallOptionRevision,
Value: spec.Revision,
}, nil
case spec.LocalPath != "":
return &cloudinit.SnapInstallData{
Option: cloudinit.InstallOptionLocalPath,
Value: spec.LocalPath,
}, nil
default:
return &cloudinit.SnapInstallData{}, nil
}
}

// resolveSecretFileContent returns file content fetched from a referenced secret object.
Expand Down Expand Up @@ -576,7 +642,11 @@ func (r *CK8sConfigReconciler) handleClusterNotInitialized(ctx context.Context,
return ctrl.Result{}, fmt.Errorf("failed to render k8sd-proxy daemonset: %w", err)
}

snapInstallData := r.resolveInPlaceUpgradeRelease(machine)
snapInstallData, err := r.getSnapInstallDataFromSpec(scope.Config.Spec)
if err != nil {
conditions.MarkFalse(scope.Config, bootstrapv1.SnapInstallDataValidatedCondition, bootstrapv1.SnapInstallValidationFailedReason, clusterv1.ConditionSeverityError, err.Error())
return ctrl.Result{Requeue: true}, fmt.Errorf("failed to get snap install data from spec: %w", err)
}

cpinput := cloudinit.InitControlPlaneInput{
BaseUserData: cloudinit.BaseUserData{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ spec:
items:
type: string
type: array
channel:
description: Channel is the channel to use for the snap install.
type: string
controlPlane:
description: CK8sControlPlaneConfig is configuration for the control
plane node.
Expand Down Expand Up @@ -389,6 +392,11 @@ spec:
the default CNI.
type: boolean
type: object
localPath:
description: |-
LocalPath is the path of a local snap file in the workload cluster to use for the snap install.
If Channel or Revision are set, this will be ignored.
type: string
nodeName:
description: |-
NodeName is the name to use for the kubelet of this node. It is needed for clouds
Expand All @@ -407,6 +415,11 @@ spec:
items:
type: string
type: array
revision:
description: |-
Revision is the revision to use for the snap install.
If Channel is set, this will be ignored.
type: string
snapstoreProxyDomain:
description: The snap store proxy domain
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,10 @@ spec:
items:
type: string
type: array
channel:
description: Channel is the channel to use for the snap
install.
type: string
controlPlane:
description: CK8sControlPlaneConfig is configuration for
the control plane node.
Expand Down Expand Up @@ -366,6 +370,11 @@ spec:
to enable the default CNI.
type: boolean
type: object
localPath:
description: |-
LocalPath is the path of a local snap file in the workload cluster to use for the snap install.
If Channel or Revision are set, this will be ignored.
type: string
nodeName:
description: |-
NodeName is the name to use for the kubelet of this node. It is needed for clouds
Expand All @@ -384,6 +393,11 @@ spec:
items:
type: string
type: array
revision:
description: |-
Revision is the revision to use for the snap install.
If Channel is set, this will be ignored.
type: string
snapstoreProxyDomain:
description: The snap store proxy domain
type: string
Expand Down
5 changes: 5 additions & 0 deletions pkg/ck8s/workload_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,11 @@ func (w *Workload) RefreshMachine(ctx context.Context, machine *clusterv1.Machin
request := apiv1.SnapRefreshRequest{}
response := &apiv1.SnapRefreshResponse{}
optionKv := strings.Split(upgradeOption, "=")

if len(optionKv) != 2 {
return "", fmt.Errorf("invalid in-place upgrade release annotation: %s", upgradeOption)
}

switch optionKv[0] {
case "channel":
request.Channel = optionKv[1]
Expand Down
10 changes: 6 additions & 4 deletions pkg/cloudinit/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type BaseUserData struct {
// KubernetesVersion is the Kubernetes version from the cluster object.
KubernetesVersion string
// SnapInstallData is the snap install data.
SnapInstallData SnapInstallData
SnapInstallData *SnapInstallData
// BootCommands is a list of commands to run early in the boot process.
BootCommands []string
// PreRunCommands is a list of commands to run prior to k8s installation.
Expand Down Expand Up @@ -65,9 +65,11 @@ func NewBaseCloudConfig(data BaseUserData) (CloudConfig, error) {

snapInstall := data.SnapInstallData
// Default to k8s version if snap install option is not set or empty.
if snapInstall.Option == "" || snapInstall.Value == "" {
snapInstall.Option = InstallOptionChannel
snapInstall.Value = fmt.Sprintf("%d.%d-classic/stable", kubernetesVersion.Major(), kubernetesVersion.Minor())
if snapInstall == nil {
snapInstall = &SnapInstallData{
Option: InstallOptionChannel,
Value: fmt.Sprintf("%d.%d-classic/stable", kubernetesVersion.Major(), kubernetesVersion.Minor()),
}
}

config := CloudConfig{
Expand Down
Loading

0 comments on commit e55ca45

Please sign in to comment.