Skip to content

Commit

Permalink
Move bootstrap/kubeadm and controlplane/kubeadm API v1beta1 webhooks …
Browse files Browse the repository at this point in the history
…to separate package
  • Loading branch information
odvarkadaniel committed Sep 19, 2023
1 parent 1735aa5 commit dd1e6be
Show file tree
Hide file tree
Showing 36 changed files with 933 additions and 917 deletions.
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ issues:
# should be removed as the referenced deprecated item is removed from the project.
- linters:
- staticcheck
text: "SA1019: (bootstrapv1.ClusterStatus|scope.Config.Spec.UseExperimentalRetryJoin|DockerMachine.Spec.Bootstrapped|machineStatus.Bootstrapped) is deprecated"
text: "SA1019: (bootstrapv1.ClusterStatus|KubeadmConfigSpec.UseExperimentalRetryJoin|scope.Config.Spec.UseExperimentalRetryJoin|DockerMachine.Spec.Bootstrapped|machineStatus.Bootstrapped) is deprecated"
# Specific exclude rules for deprecated packages that are still part of the codebase. These
# should be removed as the referenced deprecated packages are removed from the project.
- linters:
Expand Down
5 changes: 5 additions & 0 deletions bootstrap/kubeadm/api/.import-restrictions
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
rules:
- selectorRegexp: sigs[.]k8s[.]io/controller-runtime
allowedPrefixes:
- "sigs.k8s.io/controller-runtime/pkg/conversion"
forbiddenPrefixes: []
17 changes: 13 additions & 4 deletions bootstrap/kubeadm/api/v1alpha4/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,28 @@ limitations under the License.
package v1alpha4

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)

var (
// GroupVersion is group version used to register these objects.
GroupVersion = schema.GroupVersion{Group: "bootstrap.cluster.x-k8s.io", Version: "v1alpha4"}

// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)

// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
AddToScheme = schemeBuilder.AddToScheme

localSchemeBuilder = SchemeBuilder.SchemeBuilder
objectTypes = []runtime.Object{}

localSchemeBuilder = schemeBuilder
)

func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(GroupVersion, objectTypes...)
metav1.AddToGroupVersion(scheme, GroupVersion)
return nil
}
2 changes: 1 addition & 1 deletion bootstrap/kubeadm/api/v1alpha4/kubeadmconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ type KubeadmConfigList struct {
}

func init() {
SchemeBuilder.Register(&KubeadmConfig{}, &KubeadmConfigList{})
objectTypes = append(objectTypes, &KubeadmConfig{}, &KubeadmConfigList{})
}

// Encoding specifies the cloud-init file encoding.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,5 @@ type KubeadmConfigTemplateList struct {
}

func init() {
SchemeBuilder.Register(&KubeadmConfigTemplate{}, &KubeadmConfigTemplateList{})
objectTypes = append(objectTypes, &KubeadmConfigTemplate{}, &KubeadmConfigTemplateList{})
}
5 changes: 5 additions & 0 deletions bootstrap/kubeadm/api/v1beta1/.import-restrictions
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
rules:
- selectorRegexp: sigs[.]k8s[.]io/controller-runtime
allowedPrefixes: []
forbiddenPrefixes:
- "sigs.k8s.io/controller-runtime"
250 changes: 250 additions & 0 deletions bootstrap/kubeadm/api/v1beta1/kubeadmconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ limitations under the License.
package v1beta1

import (
"fmt"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation/field"

clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/cluster-api/feature"
)

// Format specifies the output format of the bootstrap data
Expand All @@ -34,6 +38,16 @@ const (
Ignition Format = "ignition"
)

var (
cannotUseWithIgnition = fmt.Sprintf("not supported when spec.format is set to: %q", Ignition)
conflictingFileSourceMsg = "only one of content or contentFrom may be specified for a single file"
conflictingUserSourceMsg = "only one of passwd or passwdFrom may be specified for a single user"
kubeadmBootstrapFormatIgnitionFeatureDisabledMsg = "can be set only if the KubeadmBootstrapFormatIgnition feature gate is enabled"
missingSecretNameMsg = "secret file source must specify non-empty secret name"
missingSecretKeyMsg = "secret file source must specify non-empty secret key"
pathConflictMsg = "path property must be unique among all files"
)

// KubeadmConfigSpec defines the desired state of KubeadmConfig.
// Either ClusterConfiguration and InitConfiguration should be defined or the JoinConfiguration should be defined.
type KubeadmConfigSpec struct {
Expand Down Expand Up @@ -107,6 +121,242 @@ type KubeadmConfigSpec struct {
Ignition *IgnitionSpec `json:"ignition,omitempty"`
}

// Default defaults a KubeadmConfigSpec.
func (c *KubeadmConfigSpec) Default() {
if c.Format == "" {
c.Format = CloudConfig
}
if c.InitConfiguration != nil && c.InitConfiguration.NodeRegistration.ImagePullPolicy == "" {
c.InitConfiguration.NodeRegistration.ImagePullPolicy = "IfNotPresent"
}
if c.JoinConfiguration != nil && c.JoinConfiguration.NodeRegistration.ImagePullPolicy == "" {
c.JoinConfiguration.NodeRegistration.ImagePullPolicy = "IfNotPresent"
}
}

// Validate ensures the KubeadmConfigSpec is valid.
func (c *KubeadmConfigSpec) Validate(pathPrefix *field.Path) field.ErrorList {
var allErrs field.ErrorList

allErrs = append(allErrs, c.validateFiles(pathPrefix)...)
allErrs = append(allErrs, c.validateUsers(pathPrefix)...)
allErrs = append(allErrs, c.validateIgnition(pathPrefix)...)

return allErrs
}

func (c *KubeadmConfigSpec) validateFiles(pathPrefix *field.Path) field.ErrorList {
var allErrs field.ErrorList

knownPaths := map[string]struct{}{}

for i := range c.Files {
file := c.Files[i]
if file.Content != "" && file.ContentFrom != nil {
allErrs = append(
allErrs,
field.Invalid(
pathPrefix.Child("files").Index(i),
file,
conflictingFileSourceMsg,
),
)
}
// n.b.: if we ever add types besides Secret as a ContentFrom
// Source, we must add webhook validation here for one of the
// sources being non-nil.
if file.ContentFrom != nil {
if file.ContentFrom.Secret.Name == "" {
allErrs = append(
allErrs,
field.Required(
pathPrefix.Child("files").Index(i).Child("contentFrom", "secret", "name"),
missingSecretNameMsg,
),
)
}
if file.ContentFrom.Secret.Key == "" {
allErrs = append(
allErrs,
field.Required(
pathPrefix.Child("files").Index(i).Child("contentFrom", "secret", "key"),
missingSecretKeyMsg,
),
)
}
}
_, conflict := knownPaths[file.Path]
if conflict {
allErrs = append(
allErrs,
field.Invalid(
pathPrefix.Child("files").Index(i).Child("path"),
file,
pathConflictMsg,
),
)
}
knownPaths[file.Path] = struct{}{}
}

return allErrs
}

func (c *KubeadmConfigSpec) validateUsers(pathPrefix *field.Path) field.ErrorList {
var allErrs field.ErrorList

for i := range c.Users {
user := c.Users[i]
if user.Passwd != nil && user.PasswdFrom != nil {
allErrs = append(
allErrs,
field.Invalid(
pathPrefix.Child("users").Index(i),
user,
conflictingUserSourceMsg,
),
)
}
// n.b.: if we ever add types besides Secret as a PasswdFrom
// Source, we must add webhook validation here for one of the
// sources being non-nil.
if user.PasswdFrom != nil {
if user.PasswdFrom.Secret.Name == "" {
allErrs = append(
allErrs,
field.Required(
pathPrefix.Child("users").Index(i).Child("passwdFrom", "secret", "name"),
missingSecretNameMsg,
),
)
}
if user.PasswdFrom.Secret.Key == "" {
allErrs = append(
allErrs,
field.Required(
pathPrefix.Child("users").Index(i).Child("passwdFrom", "secret", "key"),
missingSecretKeyMsg,
),
)
}
}
}

return allErrs
}

func (c *KubeadmConfigSpec) validateIgnition(pathPrefix *field.Path) field.ErrorList {
var allErrs field.ErrorList

if !feature.Gates.Enabled(feature.KubeadmBootstrapFormatIgnition) {
if c.Format == Ignition {
allErrs = append(allErrs, field.Forbidden(
pathPrefix.Child("format"), kubeadmBootstrapFormatIgnitionFeatureDisabledMsg))
}

if c.Ignition != nil {
allErrs = append(allErrs, field.Forbidden(
pathPrefix.Child("ignition"), kubeadmBootstrapFormatIgnitionFeatureDisabledMsg))
}

return allErrs
}

if c.Format != Ignition {
if c.Ignition != nil {
allErrs = append(
allErrs,
field.Invalid(
pathPrefix.Child("format"),
c.Format,
fmt.Sprintf("must be set to %q if spec.ignition is set", Ignition),
),
)
}

return allErrs
}

for i, user := range c.Users {
if user.Inactive != nil && *user.Inactive {
allErrs = append(
allErrs,
field.Forbidden(
pathPrefix.Child("users").Index(i).Child("inactive"),
cannotUseWithIgnition,
),
)
}
}

if c.UseExperimentalRetryJoin {
allErrs = append(
allErrs,
field.Forbidden(
pathPrefix.Child("useExperimentalRetryJoin"),
cannotUseWithIgnition,
),
)
}

for i, file := range c.Files {
if file.Encoding == Gzip || file.Encoding == GzipBase64 {
allErrs = append(
allErrs,
field.Forbidden(
pathPrefix.Child("files").Index(i).Child("encoding"),
cannotUseWithIgnition,
),
)
}
}

if c.DiskSetup == nil {
return allErrs
}

for i, partition := range c.DiskSetup.Partitions {
if partition.TableType != nil && *partition.TableType != "gpt" {
allErrs = append(
allErrs,
field.Invalid(
pathPrefix.Child("diskSetup", "partitions").Index(i).Child("tableType"),
*partition.TableType,
fmt.Sprintf(
"only partition type %q is supported when spec.format is set to %q",
"gpt",
Ignition,
),
),
)
}
}

for i, fs := range c.DiskSetup.Filesystems {
if fs.ReplaceFS != nil {
allErrs = append(
allErrs,
field.Forbidden(
pathPrefix.Child("diskSetup", "filesystems").Index(i).Child("replaceFS"),
cannotUseWithIgnition,
),
)
}

if fs.Partition != nil {
allErrs = append(
allErrs,
field.Forbidden(
pathPrefix.Child("diskSetup", "filesystems").Index(i).Child("partition"),
cannotUseWithIgnition,
),
)
}
}

return allErrs
}

// IgnitionSpec contains Ignition specific configuration.
type IgnitionSpec struct {
// ContainerLinuxConfig contains CLC specific configuration.
Expand Down
Loading

0 comments on commit dd1e6be

Please sign in to comment.