k3s/pkg/server/context.go
Brad Davidson ad41fb8c96 Create CRDs with schema
Fixes an issue where CRDs were being created without schema, allowing
resources with invalid content to be created, later stalling the
controller ListWatch event channel when the invalid resources could not
be deserialized.

This also requires moving Addon GVK tracking from a status field to
an annotation, as the GroupVersionKind type has special handling
internal to Kubernetes that prevents it from being serialized to the CRD
when schema validation is enabled.

Signed-off-by: Brad Davidson <brad.davidson@rancher.com>
2023-04-27 20:42:46 -07:00

92 lines
3.0 KiB
Go

package server
import (
"context"
"fmt"
"os"
"runtime"
helmcrd "github.com/k3s-io/helm-controller/pkg/crd"
"github.com/k3s-io/helm-controller/pkg/generated/controllers/helm.cattle.io"
addoncrd "github.com/k3s-io/k3s/pkg/crd"
"github.com/k3s-io/k3s/pkg/deploy"
"github.com/k3s-io/k3s/pkg/generated/controllers/k3s.cattle.io"
"github.com/k3s-io/k3s/pkg/version"
"github.com/pkg/errors"
"github.com/rancher/wrangler/pkg/apply"
"github.com/rancher/wrangler/pkg/crd"
"github.com/rancher/wrangler/pkg/generated/controllers/apps"
"github.com/rancher/wrangler/pkg/generated/controllers/batch"
"github.com/rancher/wrangler/pkg/generated/controllers/core"
"github.com/rancher/wrangler/pkg/generated/controllers/rbac"
"github.com/rancher/wrangler/pkg/start"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/apis/meta/v1/validation"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
type Context struct {
K3s *k3s.Factory
Helm *helm.Factory
Batch *batch.Factory
Apps *apps.Factory
Auth *rbac.Factory
Core *core.Factory
K8s kubernetes.Interface
Apply apply.Apply
}
func (c *Context) Start(ctx context.Context) error {
return start.All(ctx, 5, c.K3s, c.Helm, c.Apps, c.Auth, c.Batch, c.Core)
}
func NewContext(ctx context.Context, cfg string) (*Context, error) {
restConfig, err := clientcmd.BuildConfigFromFlags("", cfg)
if err != nil {
return nil, err
}
// Construct a custom user-agent string for the apply client used by the deploy controller
// so that we can track which node's deploy controller most recently modified a resource.
nodeName := os.Getenv("NODE_NAME")
managerName := deploy.ControllerName + "@" + nodeName
if nodeName == "" || len(managerName) > validation.FieldManagerMaxLength {
logrus.Warn("Deploy controller node name is empty or too long, and will not be tracked via server side apply field management")
managerName = deploy.ControllerName
}
restConfig.UserAgent = fmt.Sprintf("%s/%s (%s/%s) %s/%s", managerName, version.Version, runtime.GOOS, runtime.GOARCH, version.Program, version.GitCommit)
if err := crds(ctx, restConfig); err != nil {
return nil, errors.Wrap(err, "failed to register CRDs")
}
k8s, err := kubernetes.NewForConfig(restConfig)
if err != nil {
return nil, err
}
return &Context{
K3s: k3s.NewFactoryFromConfigOrDie(restConfig),
Helm: helm.NewFactoryFromConfigOrDie(restConfig),
K8s: k8s,
Auth: rbac.NewFactoryFromConfigOrDie(restConfig),
Apps: apps.NewFactoryFromConfigOrDie(restConfig),
Batch: batch.NewFactoryFromConfigOrDie(restConfig),
Core: core.NewFactoryFromConfigOrDie(restConfig),
Apply: apply.New(k8s, apply.NewClientFactory(restConfig)).WithDynamicLookup(),
}, nil
}
func crds(ctx context.Context, config *rest.Config) error {
factory, err := crd.NewFactoryFromClient(config)
if err != nil {
return err
}
types := append(helmcrd.List(), addoncrd.List()...)
factory.BatchCreateCRDs(ctx, types...)
return factory.BatchWait()
}