Skip to content

Commit

Permalink
add check for stackscript size limit when falling back to stackscript…
Browse files Browse the repository at this point in the history
…s, only check metadata for cloud-init size limit when actually using cloud-init to bootstrap
  • Loading branch information
AshleyDumaine committed Oct 10, 2024
1 parent 083e683 commit ddb3f70
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 15 deletions.
31 changes: 19 additions & 12 deletions controller/linodemachine_controller_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,10 @@ import (
"github.com/linode/cluster-api-provider-linode/util/reconciler"
)

// Size limit in bytes on the decoded metadata.user_data for cloud-init
// The decoded user_data must not exceed 16384 bytes per the Linode API
const (
maxBootstrapDataBytes = 16384
vlanIPFormat = "%s/11"
maxBootstrapDataBytesCloudInit = 16384
maxBootstrapDataBytesStackscript = 65535
vlanIPFormat = "%s/11"
)

var (
Expand Down Expand Up @@ -473,21 +472,29 @@ func setUserData(ctx context.Context, machineScope *scope.MachineScope, createCo

return err
}
if len(bootstrapData) > maxBootstrapDataBytes {
err = errors.New("bootstrap data too large")
logger.Error(err, "decoded bootstrap data exceeds size limit",
"limit", maxBootstrapDataBytes,
)

return err
}

if machineScope.LinodeMachine.Status.CloudinitMetadataSupport {
if len(bootstrapData) > maxBootstrapDataBytesCloudInit {
err = errors.New("bootstrap data too large")
logger.Error(err, "decoded bootstrap data exceeds size limit",
"limit", maxBootstrapDataBytesCloudInit,
)

return err
}
createConfig.Metadata = &linodego.InstanceMetadataOptions{
UserData: b64.StdEncoding.EncodeToString(bootstrapData),
}
} else {
logger.Info("using StackScripts for bootstrapping")
if len(bootstrapData) > maxBootstrapDataBytesStackscript {
err = errors.New("bootstrap data too large")
logger.Error(err, "decoded bootstrap data exceeds size limit",
"limit", maxBootstrapDataBytesStackscript,
)

return err
}
capiStackScriptID, err := services.EnsureStackscript(ctx, machineScope)
if err != nil {
return fmt.Errorf("ensure stackscript: %w", err)
Expand Down
39 changes: 36 additions & 3 deletions controller/linodemachine_controller_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func TestSetUserData(t *testing.T) {
},
},
{
name: "Error - SetUserData large bootstrap data",
name: "Error - SetUserData large bootstrap data for cloud-init",
machineScope: &scope.MachineScope{Machine: &v1beta1.Machine{
Spec: v1beta1.MachineSpec{
ClusterName: "",
Expand All @@ -176,15 +176,48 @@ func TestSetUserData(t *testing.T) {
Namespace: "default",
},
Spec: infrav1alpha2.LinodeMachineSpec{Region: "us-ord", Image: "linode/ubuntu22.04"},
Status: infrav1alpha2.LinodeMachineStatus{},
Status: infrav1alpha2.LinodeMachineStatus{CloudinitMetadataSupport: true},
}},
createConfig: &linodego.InstanceCreateOptions{},
wantConfig: &linodego.InstanceCreateOptions{},
expects: func(mockClient *mock.MockLinodeClient, kMock *mock.MockK8sClient) {
kMock.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, key types.NamespacedName, obj *corev1.Secret, opts ...client.GetOption) error {
cred := corev1.Secret{
Data: map[string][]byte{
"value": make([]byte, maxBootstrapDataBytesCloudInit+1),
},
}
*obj = cred
return nil
})
},
expectedError: fmt.Errorf("bootstrap data too large"),
},
{
name: "Error - SetUserData large bootstrap data for stackscript",
machineScope: &scope.MachineScope{Machine: &v1beta1.Machine{
Spec: v1beta1.MachineSpec{
ClusterName: "",
Bootstrap: v1beta1.Bootstrap{
DataSecretName: ptr.To("test-data"),
},
InfrastructureRef: corev1.ObjectReference{},
},
}, LinodeMachine: &infrav1alpha2.LinodeMachine{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster",
Namespace: "default",
},
Spec: infrav1alpha2.LinodeMachineSpec{Region: "us-ord", Image: "linode/ubuntu22.04"},
Status: infrav1alpha2.LinodeMachineStatus{CloudinitMetadataSupport: false},
}},
createConfig: &linodego.InstanceCreateOptions{},
wantConfig: &linodego.InstanceCreateOptions{},
expects: func(mockClient *mock.MockLinodeClient, kMock *mock.MockK8sClient) {
kMock.EXPECT().Get(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, key types.NamespacedName, obj *corev1.Secret, opts ...client.GetOption) error {
cred := corev1.Secret{
Data: map[string][]byte{
"value": make([]byte, maxBootstrapDataBytes+1),
"value": make([]byte, maxBootstrapDataBytesStackscript+1),
},
}
*obj = cred
Expand Down

0 comments on commit ddb3f70

Please sign in to comment.