Skip to content

Commit

Permalink
Validate external types with CRD spec
Browse files Browse the repository at this point in the history
  • Loading branch information
cartermckinnon committed Feb 27, 2024
1 parent 02bc7c2 commit 01236bd
Show file tree
Hide file tree
Showing 454 changed files with 143,711 additions and 38 deletions.
2 changes: 1 addition & 1 deletion nodeadm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ clean:

.PHONY: crds
crds: controller-gen ## Generate CustomResourceDefinition objects.
$(CONTROLLER_GEN) crd paths="./..." output:crd:artifacts:config=crds/
$(CONTROLLER_GEN) crd paths="./..." output:crd:artifacts:config=internal/api/bridge/crds

.PHONY: generate
generate: generate-code generate-doc ## Generate code and documentation.
Expand Down
1 change: 1 addition & 0 deletions nodeadm/api/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// +kubebuilder:object:generate=true
// +groupName=node.eks.aws
// +kubebuilder:validation:Optional
package v1alpha1

import (
Expand Down
4 changes: 4 additions & 0 deletions nodeadm/api/v1alpha1/nodeconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,19 @@ type NodeConfigSpec struct {
// These details can be found using the [DescribeCluster API](https://docs.aws.amazon.com/eks/latest/APIReference/API_DescribeCluster.html).
type ClusterDetails struct {
// Name is the name of your EKS cluster
// +kubebuilder:validation:Required
Name string `json:"name,omitempty"`

// APIServerEndpoint is the URL of your EKS cluster's kube-apiserver.
// +kubebuilder:validation:Required
APIServerEndpoint string `json:"apiServerEndpoint,omitempty"`

// CertificateAuthority is a base64-encoded string of your cluster's certificate authority chain.
// +kubebuilder:validation:Required
CertificateAuthority []byte `json:"certificateAuthority,omitempty"`

// CIDR is your cluster's Pod IP CIDR. This value is used to infer your cluster's DNS address.
// +kubebuilder:validation:Required
CIDR string `json:"cidr,omitempty"`

// EnableOutpost determines how your node is configured when running on an AWS Outpost.
Expand Down
21 changes: 18 additions & 3 deletions nodeadm/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,35 @@ require (
github.com/stretchr/testify v1.8.4
go.uber.org/zap v1.26.0
golang.org/x/mod v0.14.0
k8s.io/apimachinery v0.29.1
k8s.io/apiextensions-apiserver v0.29.2
k8s.io/apimachinery v0.29.2
k8s.io/cri-api v0.29.1
k8s.io/kubelet v0.29.1
sigs.k8s.io/controller-runtime v0.17.0
)

require (
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/cel-go v0.17.7 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
github.com/stretchr/objx v0.5.0 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
golang.org/x/tools v0.16.1 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/grpc v1.58.3 // indirect
k8s.io/component-base v0.29.1 // indirect
k8s.io/apiserver v0.29.2 // indirect
k8s.io/component-base v0.29.2 // indirect
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
)

require dario.cat/mergo v1.0.0 // direct
Expand Down Expand Up @@ -74,7 +89,7 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.29.1
k8s.io/api v0.29.2
k8s.io/klog/v2 v2.110.1 // indirect
k8s.io/utils v0.0.0-20240102154912-e7106e64919e // direct
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
Expand Down
106 changes: 100 additions & 6 deletions nodeadm/go.sum

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ spec:
- name: v1alpha1
schema:
openAPIV3Schema:
description: NodeConfig is the Schema for the nodeconfigs API
description: NodeConfig is the primary configuration object for `nodeadm`.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
Expand All @@ -34,42 +34,62 @@ spec:
spec:
properties:
cluster:
description: ClusterDetails contains the coordinates of your EKS cluster.
These details can be found using the [DescribeCluster API](https://docs.aws.amazon.com/eks/latest/APIReference/API_DescribeCluster.html).
properties:
apiServerEndpoint:
description: APIServerEndpoint is the URL of your EKS cluster's
kube-apiserver.
type: string
certificateAuthority:
description: CertificateAuthority is a base64-encoded string of
your cluster's certificate authority chain.
format: byte
type: string
cidr:
description: CIDR is your cluster's Pod IP CIDR. This value is
used to infer your cluster's DNS address.
type: string
enableOutpost:
description: EnableOutpost determines how your node is configured
when running on an AWS Outpost.
type: boolean
id:
description: ID is an identifier for your cluster; this is only
used when your node is running on an AWS Outpost.
type: string
name:
description: Name is the name of your EKS cluster
type: string
required:
- apiServerEndpoint
- certificateAuthority
- cidr
- name
type: object
containerd:
description: ContainerdOptions are additional parameters passed to
`containerd`.
properties:
config:
description: Config is an inline containerd config toml document
that can be provided by the user to override default generated
configurations https://github.com/containerd/containerd/blob/main/docs/man/containerd-config.toml.5.md
description: Config is inline [`containerd` configuration TOML](https://github.com/containerd/containerd/blob/main/docs/man/containerd-config.toml.5.md)
that will be [imported](https://github.com/containerd/containerd/blob/32169d591dbc6133ef7411329b29d0c0433f8c4d/docs/man/containerd-config.toml.5.md?plain=1#L146-L154)
by the default configuration file.
type: string
type: object
kubelet:
description: KubeletOptions are additional parameters passed to `kubelet`.
properties:
config:
additionalProperties:
type: object
x-kubernetes-preserve-unknown-fields: true
description: Config is a kubelet config that can be provided by
the user to override default generated configurations https://kubernetes.io/docs/reference/config-api/kubelet-config.v1/
description: Config is a [`KubeletConfiguration`](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1/)
that will be merged with the defaults.
type: object
flags:
description: Flags is a list of command-line kubelet arguments.
These arguments are amended to the generated defaults, and therefore
will act as overrides https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/
description: Flags are [command-line `kubelet`` arguments](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/).
that will be appended to the defaults.
items:
type: string
type: array
Expand Down
3 changes: 3 additions & 0 deletions nodeadm/internal/api/bridge/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ func DecodeNodeConfig(data []byte) (*internalapi.NodeConfig, error) {
if gvk.Group != api.GroupName {
return nil, fmt.Errorf("failed to decode %q, unexpected group: %s", gvk.Kind, gvk.Group)
}
if err := ValidateExternalType(obj, *gvk); err != nil {
return nil, err
}
if internalConfig, ok := obj.(*internalapi.NodeConfig); ok {
return internalConfig, nil
}
Expand Down
66 changes: 66 additions & 0 deletions nodeadm/internal/api/bridge/validation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package bridge

import (
_ "embed"
"errors"
"fmt"
"log"

"k8s.io/apiextensions-apiserver/pkg/apihelpers"
apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiservervalidation "k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
)

//go:embed crds/node.eks.aws_nodeconfigs.yaml
var customResourceDefinitionYAML []byte

var customResourceDefinition *apiextensionsv1.CustomResourceDefinition

func init() {
scheme := runtime.NewScheme()
if err := apiextensions.AddToScheme(scheme); err != nil {
panic("Failed to register apiextensions on validation scheme")
}
if err := apiextensionsv1.AddToScheme(scheme); err != nil {
panic("Failed to register apiextensionsv1 on validation scheme")
}
codecs := serializer.NewCodecFactory(scheme)
obj, gvk, err := codecs.UniversalDeserializer().Decode(customResourceDefinitionYAML, nil, nil)
if err != nil {
log.Fatalf("failed to decode CRD: %v", err)
}
if crd, ok := obj.(*apiextensionsv1.CustomResourceDefinition); !ok {
log.Fatalf("CRD YAML is not a valid apiextensionsv1.CustomResourceDefinition: %v", gvk)
} else {
customResourceDefinition = crd
}
}

func ValidateExternalType(obj runtime.Object, gvk schema.GroupVersionKind) error {
validationSchema, err := apihelpers.GetSchemaForVersion(customResourceDefinition, gvk.Version)
if err != nil {
return err
}
var internalSchemaProps *apiextensions.JSONSchemaProps
var internalValidationSchema *apiextensions.CustomResourceValidation
if validationSchema != nil {
internalValidationSchema = &apiextensions.CustomResourceValidation{}
if err := apiextensionsv1.Convert_v1_CustomResourceValidation_To_apiextensions_CustomResourceValidation(validationSchema, internalValidationSchema, nil); err != nil {
return fmt.Errorf("failed to convert CRD validation to internal version: %v", err)
}
internalSchemaProps = internalValidationSchema.OpenAPIV3Schema
}
validator, _, err := apiservervalidation.NewSchemaValidator(internalSchemaProps)
if err != nil {
return err
}
res := validator.Validate(obj)
if len(res.Errors) > 0 {
return errors.Join(res.Errors...)
}
return nil
}
14 changes: 1 addition & 13 deletions nodeadm/internal/api/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,9 @@ package api
import "fmt"

func ValidateNodeConfig(cfg *NodeConfig) error {
if cfg.Spec.Cluster.Name == "" {
return fmt.Errorf("Name is missing in cluster configuration")
}
if cfg.Spec.Cluster.APIServerEndpoint == "" {
return fmt.Errorf("Apiserver endpoint is missing in cluster configuration")
}
if cfg.Spec.Cluster.CertificateAuthority == nil {
return fmt.Errorf("Certificate authority is missing in cluster configuration")
}
if cfg.Spec.Cluster.CIDR == "" {
return fmt.Errorf("CIDR is missing in cluster configuration")
}
if enabled := cfg.Spec.Cluster.EnableOutpost; enabled != nil && *enabled {
if cfg.Spec.Cluster.ID == "" {
return fmt.Errorf("CIDR is missing in cluster configuration")
return fmt.Errorf("cidr is missing in cluster configuration")
}
}
return nil
Expand Down
26 changes: 26 additions & 0 deletions nodeadm/vendor/github.com/antlr/antlr4/runtime/Go/antlr/v4/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 01236bd

Please sign in to comment.