Skip to content
This repository was archived by the owner on Jul 30, 2021. It is now read-only.

Commit 785feff

Browse files
committed
Generate Controlplane Init Bootstrap data
This PR generates the `kubeadm init` bootstrap data Signed-off-by: Chuck Ha <[email protected]>
1 parent 9e9c219 commit 785feff

File tree

6 files changed

+113
-32
lines changed

6 files changed

+113
-32
lines changed

cloudinit/controlplane_certs.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ limitations under the License.
1616

1717
package cloudinit
1818

19-
import "errors"
19+
import "github.com/pkg/errors"
2020

2121
// Certificates is a template struct to hold certificate data
2222
type Certificates struct {

cloudinit/controlplane_init.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ limitations under the License.
1616

1717
package cloudinit
1818

19-
import (
20-
"github.com/pkg/errors"
21-
)
22-
2319
const (
2420
controlPlaneCloudInit = `{{.Header}}
2521
{{template "files" .WriteFiles}}
@@ -50,15 +46,15 @@ type ControlPlaneInput struct {
5046
func NewInitControlPlane(input *ControlPlaneInput) (string, error) {
5147
input.Header = cloudConfigHeader
5248
if err := input.Certificates.validate(); err != nil {
53-
return "", errors.Wrapf(err, "ControlPlaneInput is invalid")
49+
return "", err
5450
}
5551

5652
input.WriteFiles = certificatesToFiles(input.Certificates)
5753
input.WriteFiles = append(input.WriteFiles, input.AdditionalFiles...)
5854
userData, err := generate("InitControlplane", controlPlaneCloudInit, input)
5955
if err != nil {
60-
return "", errors.Wrapf(err, "failed to generate user data for new control plane machine")
56+
return "", err
6157
}
6258

63-
return userData, err
59+
return userData, nil
6460
}

controllers/bootstrapdata.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package controllers
18+
19+
import (
20+
"encoding/json"
21+
22+
"github.com/go-logr/logr"
23+
"github.com/pkg/errors"
24+
"sigs.k8s.io/cluster-api-bootstrap-provider-kubeadm/api/v1alpha1"
25+
"sigs.k8s.io/cluster-api-bootstrap-provider-kubeadm/cloudinit"
26+
)
27+
28+
type BootstrapDataGenerator struct {
29+
logr.Logger
30+
}
31+
32+
func (u *BootstrapDataGenerator) GenerateControlPlaneInit(config *v1alpha1.KubeadmBootstrapConfig) error {
33+
u.Info("Generating user data for first control plane")
34+
35+
// TODO: use secrets for certs, plug into kubeadm
36+
// TODO: sub in things in the cluster configuration like the cluster name and other data we can extract from the cluster object
37+
config.Spec.ClusterConfiguration.APIVersion = "v1beta1"
38+
config.Spec.ClusterConfiguration.Kind = "ClusterConfiguration"
39+
clusterdata, err := json.Marshal(config.Spec.ClusterConfiguration)
40+
if err != nil {
41+
u.Error(err, "failed to marshal cluster configuration")
42+
return errors.WithStack(err)
43+
}
44+
45+
config.Spec.ClusterConfiguration.Kind = "v1beta1"
46+
config.Spec.ClusterConfiguration.APIVersion = "InitConfiguration"
47+
initdata, err := json.Marshal(config.Spec.InitConfiguration)
48+
if err != nil {
49+
u.Error(err, "failed to marshal init configuration")
50+
return errors.WithStack(err)
51+
}
52+
53+
cicfg, err := cloudinit.NewInitControlPlane(&cloudinit.ControlPlaneInput{
54+
ClusterConfiguration: string(clusterdata),
55+
InitConfiguration: string(initdata),
56+
})
57+
if err != nil {
58+
u.Error(err, "could not create new init control plane")
59+
return err
60+
}
61+
62+
config.Status.BootstrapData = []byte(cicfg)
63+
config.Status.Ready = true
64+
return nil
65+
}

controllers/kubeadmconfig_controller.go

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2626
kubeadmv1alpha2 "sigs.k8s.io/cluster-api-bootstrap-provider-kubeadm/api/v1alpha2"
2727
"sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha2"
28+
"sigs.k8s.io/cluster-api/pkg/util"
2829
ctrl "sigs.k8s.io/controller-runtime"
2930
"sigs.k8s.io/controller-runtime/pkg/client"
3031
)
@@ -33,10 +34,21 @@ var (
3334
machineKind = v1alpha2.SchemeGroupVersion.WithKind("Machine")
3435
)
3536

36-
// KubeadmConfigReconciler reconciles a KubeadmConfig object
37+
type Locker interface {
38+
Acquire(*v1alpha2.Cluster) bool
39+
Release(*v1alpha2.Cluster) bool
40+
}
41+
42+
type bootstrapDataGenerator interface {
43+
GenerateControlPlaneInit(config *kubeadmv1alpha2.KubeadmConfig) error
44+
}
45+
46+
// KubeadmBootstrapConfigReconciler reconciles a KubeadmBootstrapConfig object
3747
type KubeadmConfigReconciler struct {
3848
client.Client
39-
Log logr.Logger
49+
ControlPlaneInitLock Locker
50+
Log logr.Logger
51+
BootstrapDataGenerator bootstrapDataGenerator
4052
}
4153

4254
// +kubebuilder:rbac:groups=bootstrap.cluster.x-k8s.io,resources=kubeadmconfigs,verbs=get;list;watch;create;update;patch;delete
@@ -108,16 +120,32 @@ func (r *KubeadmConfigReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro
108120
return ctrl.Result{}, err
109121
}
110122

111-
// maybe do something with cluster some day
112-
// maybe do something interesting here some day
123+
// Generate the cloud-init for controlplane init
124+
if r.BootstrapDataGenerator == nil {
125+
r.BootstrapDataGenerator = &BootstrapDataGenerator{
126+
Logger: r.Log.WithName("user-data-generator"),
127+
}
128+
}
129+
130+
if util.IsControlPlaneMachine(machine) {
131+
locked := r.ControlPlaneInitLock.Acquire(cluster)
132+
if locked {
133+
// Generate control plane init
134+
if err := r.BootstrapDataGenerator.GenerateControlPlaneInit(&config); err != nil {
135+
log.Error(err, "error generating control plane init")
136+
return ctrl.Result{}, err
137+
}
138+
}
139+
140+
}
141+
113142
config.Status.BootstrapData = []byte("hello world")
114143
config.Status.Ready = true
115144

116145
if err := r.Update(ctx, &config); err != nil {
117146
log.Error(err, "failed to update config")
118147
return ctrl.Result{}, err
119148
}
120-
log.Info("Updated config with bootstrap data")
121149
return ctrl.Result{}, nil
122150
}
123151

controllers/control_plane_init_locker.go renamed to locker/control_plane_init_locker.go

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package controllers
17+
package locker
1818

1919
import (
2020
"fmt"
@@ -27,28 +27,20 @@ import (
2727
clusterv2 "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha2"
2828
)
2929

30-
// ControlPlaneInitLocker provides a locking mechanism for cluster initialization.
31-
type ControlPlaneInitLocker interface {
32-
// Acquire returns true if it acquires the lock for the cluster.
33-
Acquire(cluster *clusterv2.Cluster) bool
34-
}
35-
36-
// controlPlaneInitLocker uses a ConfigMap to synchronize cluster initialization.
37-
type controlPlaneInitLocker struct {
30+
// ControlPlaneInitLocker uses a ConfigMap to synchronize cluster initialization.
31+
type ControlPlaneInitLocker struct {
3832
log logr.Logger
3933
configMapClient corev1.ConfigMapsGetter
4034
}
4135

42-
var _ ControlPlaneInitLocker = &controlPlaneInitLocker{}
43-
44-
func newControlPlaneInitLocker(log logr.Logger, configMapClient corev1.ConfigMapsGetter) *controlPlaneInitLocker {
45-
return &controlPlaneInitLocker{
36+
func NewControlPlaneInitLocker(log logr.Logger, configMapClient corev1.ConfigMapsGetter) *ControlPlaneInitLocker {
37+
return &ControlPlaneInitLocker{
4638
log: log,
4739
configMapClient: configMapClient,
4840
}
4941
}
5042

51-
func (l *controlPlaneInitLocker) Acquire(cluster *clusterv2.Cluster) bool {
43+
func (l *ControlPlaneInitLocker) Acquire(cluster *clusterv2.Cluster) bool {
5244
configMapName := fmt.Sprintf("%s-controlplane", cluster.UID)
5345
log := l.log.WithValues("namespace", cluster.Namespace, "cluster-name", cluster.Name, "configmap-name", configMapName)
5446

@@ -94,7 +86,7 @@ func (l *controlPlaneInitLocker) Acquire(cluster *clusterv2.Cluster) bool {
9486
return true
9587
}
9688

97-
func (l *controlPlaneInitLocker) Release(cluster *clusterv2.Cluster) bool {
89+
func (l *ControlPlaneInitLocker) Release(cluster *clusterv2.Cluster) bool {
9890
configMapName := fmt.Sprintf("%s-controlplane", cluster.UID)
9991
log := l.log.WithValues("namespace", cluster.Namespace, "cluster-name", cluster.Name, "configmap-name", configMapName)
10092

@@ -116,7 +108,7 @@ func (l *controlPlaneInitLocker) Release(cluster *clusterv2.Cluster) bool {
116108
return true
117109
}
118110

119-
func (l *controlPlaneInitLocker) configMapExists(namespace, name string) (bool, error) {
111+
func (l *ControlPlaneInitLocker) configMapExists(namespace, name string) (bool, error) {
120112
_, err := l.configMapClient.ConfigMaps(namespace).Get(name, metav1.GetOptions{})
121113
if apierrors.IsNotFound(err) {
122114
return false, nil

controllers/control_plane_init_locker_test.go renamed to locker/control_plane_init_locker_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package controllers
17+
package locker
1818

1919
import (
2020
"testing"
@@ -64,7 +64,7 @@ func TestControlPlaneInitLockerAcquire(t *testing.T) {
6464

6565
for _, tc := range tests {
6666
t.Run(tc.name, func(t *testing.T) {
67-
l := &controlPlaneInitLocker{
67+
l := &ControlPlaneInitLocker{
6868
log: log.ZapLogger(true),
6969
configMapClient: &configMapsGetter{
7070
configMap: tc.configMap,
@@ -120,7 +120,7 @@ func TestControlPlaneInitLockerRelease(t *testing.T) {
120120

121121
for _, tc := range tests {
122122
t.Run(tc.name, func(t *testing.T) {
123-
l := &controlPlaneInitLocker{
123+
l := &ControlPlaneInitLocker{
124124
log: log.ZapLogger(true),
125125
configMapClient: &configMapsGetter{
126126
configMap: tc.configMap,

0 commit comments

Comments
 (0)